I am trying to develop a form using Ember.js / Ember Data - here is the version information:
DEBUG: -------------------------------
DEBUG: Ember : 1.7.0
DEBUG: Ember Data : 1.0.0-beta.9
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 2.1.1
DEBUG: -------------------------------
My main handlebars template is defined as:
<script type="text/x-handlebars" data-template-name="profiles">
<div class="row">
<div class="content-header">
<h1 class="box-title">
<%= displayName %>
<div class="pull-right">
<button class="btn bg-olive btn-sm" style="margin-top:-5px;" {{action "save"}}>Save Profile Changes</button>
<button class="btn bg-orange btn-sm" style="margin-top:-5px;" {{action "cancel"}}>Cancel Changes</button>
</div>
</h1>
</div>
</div>
<div class="row" style="margin-top:10px;">
<div class="col-md-3">
{{view "personalInformation"}}
</div>
<div class="col-md-3">
{{view "contactInformation"}}
</div>
<div class="col-md-3">
{{view "addressInformation"}}
</div>
<div class="col-md-3">
{{view "emergencyContactInformation"}}
</div>
</div>
</script>
The views are defined separately. The basic personal-information handlebars template view definition:
<script type="text/x-handlebars" data-template-name="personal-information">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Personal Information</h3>
</div>
<form role="form">
<div class="box-body">
<div class="form-group">
<label for="input-firstName">First Name</label>
{{input type="text" class="form-control" placeholder="First/Given Name" value=firstName}}
</div>
<div class="form-group">
<label for="input-middleNames">Middle Names</label>
{{input type="text" class="form-control" placeholder="Middle Name(s)" value=middleNames}}
</div>
<div class="form-group">
<label for="input-lastName">Last Name</label>
{{input type="text" class="form-control" placeholder="Last/Family Name" value=lastName}}
</div>
<div class="form-group">
<label for="input-suffix">Suffix</label>
{{input type="text" class="form-control" placeholder="Suffix" value=suffix}}
</div>
<div class="form-group">
<label for="input-dob">Date of Birth</label>
{{input type="text" class="form-control" placeholder="dd/mm/yyyy" value=formattedDoB}}
</div>
<div class="form-group">
<label for="select-gender">Gender</label>
{{view Ember.Select class="form-control" content=genders value=gender}}
</div>
</div>
</form>
</div>
</script>
Portal.PersonalInformationView = Ember.View.create({
'templateName': 'personal-information'
});
The contact-information handlebars template/view definition:
<script type="text/x-handlebars" data-template-name="contact-information">
<div class="box box-primary">
<div class="box-header">
<div class="pull-left"><h3 class="box-title">Contact Information</h3></div>
<div class="pull-right box-tools"><button type="button" class="btn btn-default btm-sm" {{action "addContact"}}>+</button></div>
</div>
<form role="form">
{{#each contacts}}
<div class="box-body bg-gray" style="margin-bottom:5px;">
<div class="form-group">
<div class="pull-left">
{{view Ember.Select class="form-control" content=contactTypes value=type}}
</div>
<div class="pull-right box-tools">
<a><i id="italic_toggle_contact_{{unbound id}}" class="fa fa-chevron-circle-down fa-2x text-blue"></i></a>
<a><i class="fa fa-trash-o fa-2x text-orange" {{action "deleteContact" id}}></i></a>
</div>
<div> </div>
</div>
<div id="div_toggle_contact_{{unbound id}}" class="form-group" style="display:none;">
<div class="pull-left" style="margin-top:3px;">
{{view Ember.Select class="form-control" content=countryCodes value=code}}
</div>
<div class="pull-left" style="margin-top:3px;">
{{input type="text" class="form-control" value=number}}
</div>
<div> </div>
</div>
</div>
{{/each}}
</form>
</div>
</script>
Portal.ContactInformationView = Ember.View.create({
'templateName': 'contact-information',
'click': function(evt) {
// Step #1: Stop the event from bubbling...
evt.preventDefault();
evt.stopPropagation();
// Step #2: If this is for collapsing / expanding contacts...
if(evt.target.id.indexOf('italic_toggle') >= 0) {
var sourceElem = $(evt.target);
sourceElem.toggleClass('fa-chevron-circle-down');
sourceElem.toggleClass('fa-chevron-circle-up');
var targetElem = $('#' + evt.target.id.replace('italic', 'div'));
targetElem.slideToggle(600);
}
}
});
The address-information handlebars template/view definition:
<script type="text/x-handlebars" data-template-name="address-information">
<div class="box box-primary">
<div class="box-header">
<div class="pull-left"><h3 class="box-title">Location Information</h3></div>
<div class="pull-right box-tools"><button type="button" class="btn btn-default btm-sm" {{action "addAddress"}}>+</button></div>
</div>
<form role="form">
{{#each addresses}}
<div class="box-body bg-gray" style="margin-bottom:5px;">
<div class="form-group">
<div class="pull-left">
{{view Ember.Select class="form-control" content=addressTypes value=type}}
</div>
<div class="pull-right box-tools">
<a><i id="italic_toggle_address_{{unbound id}}" class="fa fa-chevron-circle-down fa-2x text-blue"></i></a>
<a><i class="fa fa-trash-o fa-2x text-orange" {{action "deleteAddress" id}}></i></a>
</div>
<div> </div>
</div>
<div id="div_toggle_address_{{unbound id}}" style="display:none;">
<div class="form-group" style="margin-top:3px;">
{{view Ember.Select class="form-control" content=countries value=country}}
{{view Ember.Select class="form-control" content=states value=state}}
{{view Ember.Select class="form-control" content=cities value=city}}
{{input type="text" class="form-control" placeholder="PIN Code" value=pincode}}
</div>
<div class="form-group">
{{input type="text" class="form-control" placeholder="Line #1" value=line1}}
{{input type="text" class="form-control" placeholder="Line #2" value=line2}}
{{input type="text" class="form-control" placeholder="Line #3" value=line3}}
{{input type="text" class="form-control" placeholder="Area" value=area}}
</div>
</div>
</div>
{{/each}}
</form>
</div>
</script>
Portal.AddressInformationView = Ember.View.create({
'templateName': 'address-information',
'click': function(evt) {
// Step #1: Stop the event from bubbling...
evt.preventDefault();
evt.stopPropagation();
// Step #2: If this is for collapsing / expanding addresses...
if(evt.target.id.indexOf('italic_toggle') >= 0) {
var sourceElem = $(evt.target);
sourceElem.toggleClass('fa-chevron-circle-down');
sourceElem.toggleClass('fa-chevron-circle-up');
var targetElem = $('#' + evt.target.id.replace('italic', 'div'));
targetElem.slideToggle(600);
}
}
});
The emergency-contact-information handlebars template/view definition:
<script type="text/x-handlebars" data-template-name="emergency-contact-information">
<div class="box box-primary">
<div class="box-header">
<div class="pull-left"><h3 class="box-title">Emergency Contacts</h3></div>
<div class="pull-right box-tools"><button type="button" class="btn btn-default btm-sm" {{action "addEmergencyContact"}}>+</button></div>
</div>
<form role="form">
{{#each emergencyContacts}}
<div class="box-body bg-gray" style="margin-bottom:5px;">
<div class="form-group">
<div class="pull-left">
{{input type="text" class="form-control" placeholder="Contact Name" value=name}}
</div>
<div class="pull-right box-tools">
<a><i id="italic_toggle_emergency_contact_{{unbound id}}" class="fa fa-chevron-circle-down fa-2x text-blue"></i></a>
<a><i class="fa fa-trash-o fa-2x text-orange" {{action "deleteEmergencyContact" id}}></i></a>
</div>
<div> </div>
</div>
<div id="div_toggle_emergency_contact_{{unbound id}}" class="form-group" style="display:none;">
<div class="pull-left" style="margin-top:3px;">
{{view Ember.Select class="form-control" content=countryCodes value=code}}
</div>
<div class="pull-left" style="margin-top:3px;">
{{input type="text" class="form-control" value=number}}
</div>
<div> </div>
</div>
</div>
{{/each}}
</form>
</div>
</script>
Portal.EmergencyContactInformationView = Ember.View.create({
'templateName': 'emergency-contact-information',
'click': function(evt) {
// Step #1: Stop the event from bubbling...
evt.preventDefault();
evt.stopPropagation();
// Step #2: If this is for collapsing / expanding contacts...
if(evt.target.id.indexOf('italic_toggle') >= 0) {
var sourceElem = $(evt.target);
sourceElem.toggleClass('fa-chevron-circle-down');
sourceElem.toggleClass('fa-chevron-circle-up');
var targetElem = $('#' + evt.target.id.replace('italic', 'div'));
targetElem.slideToggle(600);
}
}
});
The route, controller, and model definitions are here:
Portal.ProfilesRoute = Ember.Route.extend({
'setupController': function(controller, model) {
controller.set('model', model);
},
'model': function(params) {
return this.store.find('profile', params.userId);
},
'actions': {
'didTransition': function() {
setTimeout(function() {
$("#input-dob").inputmask("dd/mm/yyyy", {"placeholder": "dd/mm/yyyy"});
}, 250);
}
}
});
Portal.ProfilesController = Ember.ObjectController.extend({
'actions': {
'addContact': function() {
var user = this.get('model'),
newid = Portal.generateUUID();
user.get('contacts').addObject(this.store.createRecord('contact', {
'id': newid,
'dbid': newid
}));
},
'deleteContact': function(id) {
var user = this.get('model');
this.store.find('contact', id)
.then(function(contact) {
user.get('contacts').removeObject(contact);
contact.deleteRecord();
});
},
'addAddress': function() {
var user = this.get('model'),
newid = Portal.generateUUID();
user.get('addresses').addObject(this.store.createRecord('address', {
'id': newid,
'dbid': newid
}));
},
'deleteAddress': function(id) {
var user = this.get('model');
this.store.find('address', id)
.then(function(address) {
user.get('addresses').removeObject(address);
address.deleteRecord();
});
},
'addEmergencyContact': function() {
var user = this.get('model'),
newid = Portal.generateUUID();
user.get('emergencyContacts').addObject(this.store.createRecord('emergencyContact', {
'id': newid,
'dbid': newid
}));
},
'deleteEmergencyContact': function(id) {
var user = this.get('model');
this.store.find('emergencyContact', id)
.then(function(emergencyContact) {
user.get('emergencyContacts').removeObject(emergencyContact);
emergencyContact.deleteRecord();
});
},
'save': function() {
this.model.save();
},
'cancel': function() {
this.model.get('contacts').content.invoke('rollback');
this.model.get('addresses').content.invoke('rollback');
this.model.rollback();
}
}
});
Portal.Profile = DS.Model.extend({
'firstName': DS.attr('string'),
'middleNames': DS.attr('string'),
'lastName': DS.attr('string'),
'suffix': DS.attr('string'),
'dob': DS.attr('date'),
'gender': DS.attr('string'),
'contacts': DS.hasMany('contact'),
'addresses': DS.hasMany('address'),
'emergencyContacts': DS.hasMany('emergencyContact'),
'formattedDoB': function(key, value, prevValue) {
if(arguments.length <= 1) {
return moment(this.get('dob')).format('DD/MM/YYYY');
}
// Set the new DOB
var newDoB = moment(value, 'DD/MM/YYYY');
if(newDoB.isValid()) {
this.set('dob', newDoB.toDate());
}
}.property('dob'),
'genders': ['Male', 'Female']
});
Portal.Contact = DS.Model.extend({
'dbid': DS.attr('string'),
'type': DS.attr('string'),
'code': DS.attr('string'),
'number': DS.attr('string'),
'contactTypes': ['Home Landline', 'Office Landline', 'Other Landline', 'Personal Mobile', 'Office Mobile', 'Other Mobile', 'Other'],
'countryCodes': ['1', '91']
});
Portal.Address = DS.Model.extend({
'dbid': DS.attr('string'),
'type': DS.attr('string'),
'line1': DS.attr('string'),
'line2': DS.attr('string'),
'line3': DS.attr('string'),
'area': DS.attr('string'),
'city': DS.attr('string'),
'state': DS.attr('string'),
'country': DS.attr('string'),
'pincode': DS.attr('string'),
'addressTypes': ['Home', 'Office', 'Other'],
'countries': ['India', 'USA'],
'states': function() {
var countryStates = {
'India': ['Andhra Pradesh', 'Telangana'],
'USA': ['Alabama', 'Kentucky']
};
return countryStates[this.get('country')];
}.property('country'),
'cities': function() {
var stateCities = {
'Andhra Pradesh': ['Vijayawada', 'Guntur', 'Tirupati'],
'Telangana': ['Hyderabad', 'Secunderabad']
};
return stateCities[this.get('state')];
}.property('state')
});
Portal.EmergencyContact = DS.Model.extend({
'dbid': DS.attr('string'),
'code': DS.attr('string'),
'number': DS.attr('string'),
'countryCodes': ['1', '91']
});
When I transition into this route the first time, it works perfectly well. The moment I transition to the home / other route, and try to transition back to this route, Ember throws an assertion failed error:
Uncaught Error: Assertion Failed: calling set on destroyed object" (ember.js:3722)
What am I doing wrong?