Skip to content
Fix Code Error

Why is Ember throwing “Uncaught Error: Assertion Failed: calling set on destroyed object” at ember.js:3722?

April 15, 2021 by Code Error
Posted By: Anonymous

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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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?

Solution

Here are 2 things that I spotted out from your code.

First thing:

You have your ember route mixed together.
And you should be clear about singular/plural name convention in routing.

Portal.ProfilesRoute refers to set of of profiles.
Portal.ProfileRoute refers to 1 individual profile.

Because you define both within Portal.ProfilesRoute. First time click Ember will automatically routing assume you are return same model, thus doesn’t even call your route. But then when you try to navigate back which is when the model hook actually called your routing, and end up with the error.

second thing
kind of related to thing 1:

'setupController': function(controller, model) {
        controller.set('model', model);
    },

    'model': function(params) {
        return this.store.find('profile', params.userId);
    }

either one but not both. for example, use setupController if you want to do something with the model.

'setupController': function(controller, model) {
            //do something to the model if you want to 
            // maybe change some attribute 
             model.set('name','blah blah');
            controller.set('model', model);
        },

otherwise just do

'model': function(params) {
        return this.store.find('profile', params.userId);
    },

but yes, as mentioned in thing 1, this should be in singular route which is ProfileRoute

Hope it helps!

Answered By: Anonymous

Related Articles

  • Can't correctly import external JS into Aurelia application…
  • Jquery fadeToggle Trouble
  • Vuejs not reading property from mixins and export NOT FOUND…
  • Is CSS Turing complete?
  • After a little scroll, the sticky navbar just is not fixed…
  • Ember-CLI Not Resolving Ember 2.0
  • Navbar not filling width of page when reduced to mobile view
  • error LNK2005: ✘✘✘ already defined in…
  • EmberJS - how to access parent controller from within child…
  • laravel vuejs/axios put request Formdata is empty

Disclaimer: This content is shared under creative common license cc-by-sa 3.0. It is generated from StackExchange Website Network.

Post navigation

Previous Post:

Cannot pass multiple arguments in vuex actions

Next Post:

Backbone.js – Pass variable from route to view/collection/model

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • Get code errors & solutions at akashmittal.com
© 2022 Fix Code Error