Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Durandal view composition order

Tags:

durandal

Durandal 2.0 - view composition order

I have view, that has a number of child views that I am using just to break up the HTML into separate files.

index.html(index.js)
     - menu.html
     - header.html
     - footer.html

The menu view is populated by the index view after it's loaded.

Inside the index.html I compose the menu view like this (there is no module menu.js, just html composition here):

<!--ko compose: {  view: 'menu'}--><!--/ko-->

The problem is the order of the view composition.

I have an attached event wired up in index.js that then calls a function to populate the menu div that's sat in menu.html.

But, the attached view event is called before the menu.html view has been composed.

The events looks something like this from the console:

Binding views/footer 
Binding views/index 
binding complete: <section data-view=​"views/​index" style=​"display:​ none;​">​…​</section>​
[Index]  Main View Attached 
Binding views/header 
Binding views/menu 
Binding views/menudropdown

So, the main view is attached before the children.

Is there a way to change the composition order, or wait for all the child views to be composed/loaded before the main view is attached/complete?

Thanks

like image 440
John Lucas Avatar asked Jan 26 '26 00:01

John Lucas


1 Answers

The short answer is "no" - you can't change the composition order.

The longer answer: perhaps I've misunderstood, but it sounds a little bit suspicious that you're populating the menu div from your view model. Could you use a custom binding to do this instead? If you can do it in a binding, then you could have a look at using a Delayed Binding Handler. From the documentation:

Sometimes your binding handler needs to work with an element only after it is attached to the DOM and when the entire composition of the view is complete. An example of this is any code that needs to measure the size of an HTML element. Durandal provides a way to register a knockout binding handler so that it does not execute until the composition is complete. To do this, use composition.addBindingHandler.

Alternatively, if you're happy with whatever code is running in your viewModel, you probably want to use the compositionComplete event rather than the attached event. From memory, the attached events run from parent to child (which is why the event is being called on index before the menu has been composed). In contrast, compositionComplete bubbles from child to parent:

Finally, when the entire composition process is complete, including any parent and child compositions, the composition engine will call the compositionComplete(view, parent) callback, bubbling from child to parent.

You can attach a compositionComplete handler on your viewModel in the same fashion as an activate method:

// Secured Shell
define([], function () {
    var viewModel = {
        activate: function () {
            // do stuff
        },

        compositionComplete: function (parent, child, settings) {
            // do more stuff
            debugger;
        }
    };

    return viewModel;
});

Hope that helps.

like image 135
gerrod Avatar answered Jan 28 '26 21:01

gerrod



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!