EmberJS - RequireJS - How to connect a view/templa

2019-05-31 00:47发布

问题:

Again a question due to EmberJS evolving quite fast :)

[EDIT]
I am using EmberJS from github. This is the version I am using
https://github.com/emberjs/ember.js/tree/c87ad9fc13f7883e7b898c9fb9b1630cb2fc9bf1
[/EDIT]

This question is a follow up of EmberJS - Manually bind controller to view
But you don't need to read it to understand the following question.

I have an EmberJS application and I am using requireJS to load my controllers and views for the section of the application the router is routing to.

My main index.html has an {{outlet}} where the ApplicationView will be added.
My ApplicationView has 3 child views - header, menu and container - as follow

require
(
    [
        'app/app',
        'app/common/views/menu',
        'ember'
    ],
    /**
     * Main application view
     *
     * @param App
     */
    function (App)
    {
        App.ApplicationView = Ember.ContainerView.extend
        ({
            childViews   : ['headerView', 'menuView', 'containerView'],
            headerView   : App.HeaderView,
            menuView     : App.MenuView,
            containerView: App.ContainerView
        });
    }
);

My ContainerView is as follow

require
(
    [
        'app/app',
        'text!app/common/templates/container.hbs',
        'ember'
    ],
    /**
     * View to clear completed tasks
     *
     * @param App
     * @param template
     */
    function( App, template )
    {
        App.ContainerView = Ember.View.extend
        ({
            template: Ember.Handlebars.compile( template ),
            what: 'container view'
        })
    }
);

and its template like this
[EDIT]
The template is in its own file app/common/templates/container.hbs. I don't want to define the templates with script tag in the html
[/EDIT]

<div id="container" class="container">
    my main content !!!
    {{outlet}}
</div>

Now I have a route, where I would like to render a template/view into the container main outlet (I also tried to name the outlet).

I would like to have something like this in my route. Please note that the controller and view haven't been previously loaded and will be loaded now by requireJS before the execution of the function.

define
(
    [
        'app/app',
        'app/library/controllers/library',
        'app/library/views/main',
        'ember'
    ],
    function (App)
    {
        App.LibraryRoute = Ember.Route.extend
        ({
            setupControllers: function(controller, model)
            {
                this.set('controller', this.container.lookup('controller:library') );
            },

            renderTemplates : function()
            {   
                this.render
                (   'library',
                    {
                    //  can I specify the view like so? 
                    //  It seems not as the container view is not part of the active views. 
                    //  can I specify the view like so?How to add it to the activeViews?
                    //  into: 'container',

                    //  I also tried to do
                    //  outlet: 'container'
                    //  with the outlet in the container template beeing named container, this doesn't work either
                        controller: this.controller
                    }
                );

//                This is what I am aiming for in the future, meaning loading resources only if the user is navigating to those
/*                require
                 (
                 [
                     'app/library/controllers/library',
                     'app/library/views/main',
                     'app/library/models/library'
                 ],
                 function()
                 {
                    // render template / view
                 )*/
            }
        })
    }
);

The LibraryView is like this

require
(
    [
        'app/app',
        'text!app/library/templates/main.hbs',
        'ember'
    ],
    /**
     * View to clear completed tasks
     *
     * @param App
     * @param template
     */
    function( App, template )
    {
        App.LibraryView = Ember.View.extend
        ({
            template: Ember.Handlebars.compile( template ),
            what :'library view'
        });
    }
);

and the controller for this view is like this

require
(
    [
        'app/app',
        'ember'
    ],
    /**
     * Library controller
     */
    function(App)
    {
        App.LibraryController = Ember.ArrayController.extend
        ({
            needs: 'menu',
            content: []
        });
    }
)

The question can be resumed to this
How to connect a view/template to an outlet of a child view (loaded before or after the app is initialized, DOM Loaded)?

I have created a repo on GitHub here https://github.com/zeflasher/ember-require-js for you to check the code and maybe helping me out fixing this.

Thanks a lot for any help you could provide!!! Cheers, Xavier

[EDIT #4]
I wonder if my problem is related to one of those bugs as I am specifying my template
https://github.com/emberjs/ember.js/commit/712e2b62f79577b84630a99e80c043f751a67fe4
https://github.com/emberjs/ember.js/commit/9bcc0cd87c587affc0e60030b2dac1174f820dbf
[/EDIT #4]

[EDIT #5]
Updated the github project to use ember commit ea6922f (4 days old at the time of writting)
Still not working an raising more question :)
[/EDIT #5]

[EDIT #6]
I have updated the github repo.
Now one branch (working-no-containerview) render my view in the outlet when the application is a normal view haveing an outlet.

The master branch is the non working example (nothing is rendered in the container template/view outlet). I though that as the child view aren't part of the _activeViews when trying to connect the outlet it will fail, so I have even tried to add my child 'container' view to the active view using the following code in the ApplicationView

require
(
    [
        'app/app',
        'app/common/views/menu',
        'ember'
    ],
    /**
     * Main application view
     *
     * @param App
     */
    function (App)
    {
        App.ApplicationView = Ember.ContainerView.extend
        ({
            childViews   : ['headerView', 'menuView', 'containerView'],
            headerView   : App.HeaderView,
            menuView     : App.MenuView,
            containerView: App.ContainerView,
            init: function()
            {
                App.__container__.lookup('router:main')._connectActiveView('container', App.__container__.lookup('view:container'));

                this._super();
            }
        });
        return App.ApplicationView;
    }
);

Which add it to the activeViews, but still is not working, added that it looks terribly wrong to go that deep in the framework to have something this simple working (which well still doesn't in my casE), so I really think I missed something essential here.
[/EDIT #6]

回答1:

This is not a bug. ContainerViews simply don't render a template. See the api docs for Ember.ContainerView

A template, templateName, defaultTemplate, layout, layoutName or defaultLayout property on a container view will not result in the template or layout being rendered. The HTML contents of a Ember.ContainerView's DOM representation will only be the rendered HTML of its child views.

If you want to render an outlet in a template you can do this in a subclass of Ember.View without any problem. But as stated above this will not work for ContainerView nor on CollectionView I think because this is a subclass of Ember.ContainerView.

I also commented on your issue: https://github.com/emberjs/ember.js/issues/1795#issuecomment-12453015 and I think you can close it yourself.

Best regards, Mike