简体   繁体   中英

EmberJS - how to access parent controller from within child controller?

I have a ProfilesController and a ProfileController which represents a single Profile.

// Profiles listing
App.ProfilesController = Ember.ArrayController.extend({

});

// Single Profile representation
App.ProfileController = Ember.ObjectController.extend({

    isActive: false,

    actions: {

        edit: function() {

            // TODO: disable all profiles
            // does not work ... parentController is undefined. pseudo code only!
            this.get('parentController.children').forEach(function(profile) {
                profile.set('isActive', false);
            });

            // enable current profile
            this.set('isActive', true);
        }
    }
});

Note that this is not the complete code, these 2 controllers have more code in my application and there is also a ProfileView which makes the profile listing possible.

The important part is how do I access the parent ProfilesController (the ArrayController) from within a ProfileController?

I have tried (in the edit action):

this.get('parent') // => undefined
this.get('parentController') // => null
this.get('target') // => null

Edit : meanwhile I went down the object tree and I came up with an incredibly hacky but working solution:

// disable all profiles
this.get('controllers.profiles.target._activeViews.profiles.0._childViews.0._childViews').forEach(function(childView) {
    childView.get('_childViews.0.controller').set('isActive', false);
});

It works until I change something in my templates structure I suppose. There has to be a cleaner way to do this :-D

Edit 2 : To clarify a bit more, here is my Profiles Template, where profiles is a collection of Profile Models (not Controllers! Every model is represented by a Controller, since I have to store application state like current active profile etc.) :

{{#each profile in profiles}}
    {{view App.ProfileView profileBinding=profile}}
{{/each}}

and the ProfileView

App.ProfileView = Ember.View.extend({

     templateName: 'profiles/profile',

     init: function() {
         this._super();
         var profile = this.get('profile');

         // Here I explicitely create a ProfileController instance, 
         // otherwise ProfilesController would be used instead of ProfileController 
         // because in EmberJS by default the View's controller is always the parent controller
         this.set('controller', App.ProfileController.create());
         var controller = this.get('controller');
         controller.set('profile', profile);            
     }
});

You can set the itemController property in your each loop so that you don't have to manually create ProfileController s.

{{#each profile in profiles itemController="profile"}}
    {{view App.ProfileView profileBinding=profile}}
{{/each}}

Then you can use needs to make sure that a reference to the ProfilesController is injected into each ProfileController . You'd use this.get('controllers.profiles') to access the ArrayController itself. If you're doing things The Ember Way, you'd want to access the content property of that controller ( this.get('controllers.profiles.content') ). It looks like you're not doing it The Ember Way, and instead have the collection to the profiles property of that controller instead of to the content property. In that case you'd use this.get('controllers.profiles.profiles') . The first instance of profiles gets the ProfilesController , the second instance gets the profiles property that is set on that controller.

App.ProfileController = Ember.ObjectController.extend({
    needs: ['profiles'],
    actions: {
        edit: function() {

            this.get('controllers.profiles.profiles').forEach(function(profile) {
                profile.set('isActive', false);
            });

            // enable current profile
            this.set('isActive', true);
        }
    }
});

Do you want to make it implicit (like in any other language to use super) or is it sufficient to name the controllers you want to access explicit?

See this link: http://eviltrout.com/2013/02/04/ember-pre-1-upgrade-notes.html

In your case it would be:

App.ProfileController = Ember.ObjectController.extend({
    needs: ['profiles'],
    actions: {
        edit: function() {

            this.get('controllers.profiles').forEach(function(profile) {
                profile.set('isActive', false);
            });

            // enable current profile
            this.set('isActive', true);
        }
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM