Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Hard to override durandal.js behavior as long as the module pattern is used. #74

Closed
rgullhaug opened this Issue Feb 26, 2013 · 22 comments

Comments

Projects
None yet
5 participants

As I have mentioned in another thread I'm working on getting Durandal to work together with Kendoui databinding. To be able to do that I need to override the ViewModelBinder.bind() method. I would like to do this without changing the original Durandal code, but just add new code - in that way I can customize the behavior of Durandal, but still be able to update the durandal code without loosing my customizations. But when it comes to the ViewModelBinder.bind function I'm not able to override this method, without at the same time loose access to the doBind function (which I don't want to override).

It would be nice to override ViewModelBinder.bind() with something like this:
bind: function (obj, view) {
doBind(obj, view, function () {
var kendoElements = $(view).find('[data-mvvm-framework=kendo]');
$(kendoElements).wrapAll('

');
for (var i = 0; i < kendoElements.length; i++) {
kendo.bind(kendoElements[i], obj.viewModel);
}

            ko.applyBindings(obj, view);
            if (obj.setView) {
                obj.setView(view);
            }
        });
    }

But this will fail because doBind() is not accessible. Do you see a solution for this?
I think that in this case the module pattern is making it impossible to override bind() if you not at the same time also override doBind() - http://edspencer.net/2009/10/javascript-module-pattern-overused-dangerous-and-bloody-annoying.html

It can of course be solved as simple as this in ViewModelBinder.js (see the last code line):
return {
bindContext: function(bindingContext, view, obj) {
if (obj) {
bindingContext = bindingContext.createChildContext(obj);
}

        doBind(bindingContext, view, function() {
            ko.applyBindings(bindingContext, view);
            if (obj && obj.setView) {
                obj.setView(view);
            }
        });
    },
    bind: function(obj, view) {
        doBind(obj, view, function() {
            ko.applyBindings(obj, view);
            if (obj.setView) {
                obj.setView(view);
            }
        });
    },
    doBind: doBind  // makes doBind public
}; 

But then doBind could just have been public in the first place.

Hmm... how can I add code and have it nice formatted? I just pasted the code directly in the editor and it ends up like you see above. Some of it is nice formatted, but not all.

Owner

EisenbergEffect commented Feb 26, 2013

Github markdown allows you to use the 3 backticks before and after your
code block. Google github flavored markdown.

On Tue, Feb 26, 2013 at 11:16 AM, rgullhaug notifications@github.comwrote:

Hmm... how can I add code and have it nice formatted? I just pasted the
code directly in the editor and it ends up like you see above. Some of it
is nice formatted, but not all.


Reply to this email directly or view it on GitHubhttps://github.com/BlueSpire/Durandal/issues/74#issuecomment-14123288
.

Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project
850.264.3996

Contributor

RainerAtSpirit commented Feb 26, 2013

see https://help.github.com/articles/github-flavored-markdown
back ticks are your friend ;-)
e.g. start with javascript javascript in between end with

return {
 bindContext: function(bindingContext, view, obj) {
 if (obj) {
 bindingContext = bindingContext.createChildContext(obj);
 }
  doBind(bindingContext, view, function() {
            ko.applyBindings(bindingContext, view);
            if (obj && obj.setView) {
                obj.setView(view);
            }
        });
    },
    bind: function(obj, view) {
        doBind(obj, view, function() {
            ko.applyBindings(obj, view);
            if (obj.setView) {
                obj.setView(view);
            }
        });
    },
    doBind: doBind  // makes doBind public
}; 
Contributor

RainerAtSpirit commented Feb 26, 2013

+1 for the ability to support external UI frameworks like kendoUI.
With that said what would be considered best practice for those kinds of modifications as of today? I can see one drastic approach by swapping out viewmodel.js with an modified version that still exposes the same public interface bindand bindContext, but of course that would lead to issues with future Durandal upgrades.

Owner

EisenbergEffect commented Feb 26, 2013

I will expose a hook into the do bind functionality, most likely, to add
pre/post logic. How does that sound?

On Tue, Feb 26, 2013 at 11:53 AM, Rainer Wittmann
notifications@github.comwrote:

+1 for the ability to support external UI frameworks like kendoUI.
With that said what would be considered best practice for those kinds of
modifications as of today? I can see one drastic approach by swapping out
viewmodel.js with an modified version that still exposes the same public
interface bindand bindContext, but of course that would lead to issues
with future Durandal upgrades.


Reply to this email directly or view it on GitHubhttps://github.com/BlueSpire/Durandal/issues/74#issuecomment-14125470
.

Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project
850.264.3996

Contributor

RainerAtSpirit commented Feb 26, 2013

IMO pre/post logic on dobind should cover the kendoUI use case, which only requires a change on bind, but probably best to let @rgullhaug judge on this.

As @RainerAtSpirit says it is an option to swap out some of the durandal code with custom code, but that will make it hard to upgrade to a newer version of Durandal. Some hooks like you suggest @EisenbergEffect seems like a good idea :)

Owner

EisenbergEffect commented Feb 27, 2013

Hey all. I've got another really interesting use case for this, so we will definitely get the hooks in there soon.

Contributor

RainerAtSpirit commented Feb 27, 2013

Thanks for the heads up. What kind of use case are you talking about?

Owner

EisenbergEffect commented Feb 27, 2013

Well...that is a secret for now :) But, in the next couple of weeks you
might see an "Experimental" folder show up in the solution with something
fun I want to try out related to databinding.

On Wed, Feb 27, 2013 at 9:37 AM, Rainer Wittmann
notifications@github.comwrote:

Thanks for the heads up. What kind of use case are you talking about?


Reply to this email directly or view it on GitHubhttps://github.com/BlueSpire/Durandal/issues/74#issuecomment-14176584
.

Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project
850.264.3996

Contributor

RainerAtSpirit commented Feb 27, 2013

There you go. Experiments and fun, what a concept ;-).

@ghost ghost assigned EisenbergEffect Feb 28, 2013

Perfect! Thank you so much for fixing this.

Looking forward to the secret databinding related stuff:)

Contributor

RainerAtSpirit commented Mar 1, 2013

Me too :).
@rgullhaug BTW There's another pattern that would allow you to work with KendoUI widgets that doesn't requiere usage of the beforeBindand afterBindhooks. If you'd ommit the declarative declaration and configure widgets by using JavaScript you can do something along the following line.
Within your view configure an element that will be converted to a Kendo widget e.g. <div class=".grid"></div>.
Within your viewModel use the activate to accomplish setup tasks like data retrieval e.g.

// Make sure too enable 'active : true' in the compose directive
activate: function () {
  // Grab some data as promise
  system.log('ViewModel Activating', this);
},...

Use viewModal viewAttachedto convert the dom element into a Kendo widget e.g.

viewAttached: function (elem) {
  // Resolve the promise and do something ...
  system.log('Attached to elem', elem);
  $(elem).find('.grid').kendoGrid(//kendo Widget configuration goes here);
}

I have a prototpe of this pattern running here, but didn't test it intensively. @EisenbergEffect Do you see some pros/cons in this approach?

KendoUI released its 2013 beta lately and by glancing through their documentation there seems to be a third option available as well (might be available in the current version as well, but just stumbled over this yesterday)..
http://docs.kendoui.com/howto/declarative_initialization#important-things-to-know

Kendo UI is not the only framework that uses data attributes for binding. In fact, its pretty common. If you find yourself in a situation where you need to mitigate collisions with Kendo UI and some other JS library, you can provide a namespace for Kendo UI and then reference that namespace instead.
kendo.ns="kendo";
// then data-bind="value: someValue"
// becomes data-kendo-bind="value: someValue"

Owner

EisenbergEffect commented Mar 1, 2013

I think it's generally best not to use viewAttached unless you really,
really have to. If it can be done in binding, then that's the way to go.
So, if I were using Kendo, I would plug into the binding hooks.

On Fri, Mar 1, 2013 at 4:26 AM, Rainer Wittmann notifications@github.comwrote:

Me too :).
@rgullhaug https://github.com/rgullhaug BTW There's another pattern
that would allow you to work with KendoUI widgets that doesn't requiere
usage of the beforeBindand afterBindhooks. If you'd ommit the declarative
declaration and configure widgets by using JavaScript you can do something
along the following line.
Within your view configure an element that will be converted to a Kendo
widget e.g.

.
Within your viewModel use the activate to accomplish setup tasks like
data retrieval e.g.

// Make sure too enable 'active : true' in the compose directiveactivate: function () {
// Grab some data as promise
system.log('ViewModel Activating', this);},...

Use viewModal viewAttachedto convert the dom element into a Kendo widget
e.g.

viewAttached: function (elem) {
// Resolve the promise and do something ...
system.log('Attached to elem', elem);
$(elem).find('.grid').kendoGrid(//kendo Widget configuration goes here);}

I have a prototpe of this pattern running here, but didn't test it
intensively. @EisenbergEffect https://github.com/EisenbergEffect Do you
see some pros/cons in this approach?

KendoUI released its 2013 beta lately and by glancing through their
documentation there seems to be a third option available as well (might be
available in the current version as well, but just stumbled over this
yesterday)..

http://docs.kendoui.com/howto/declarative_initialization#important-things-to-know

Kendo UI is not the only framework that uses data attributes for binding.
In fact, its pretty common. If you find yourself in a situation where you
need to mitigate collisions with Kendo UI and some other JS library, you
can provide a namespace for Kendo UI and then reference that namespace
instead.
kendo.ns="kendo";
// then data-bind="value: someValue"
// becomes data-kendo-bind="value: someValue"


Reply to this email directly or view it on GitHubhttps://github.com/BlueSpire/Durandal/issues/74#issuecomment-14279511
.

Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project
850.264.3996

Owner

EisenbergEffect commented Mar 1, 2013

Also, when one of you gets this working. I would love for you to send me
the code that you added. I think it would make a nice addition to the docs
on how to integrate with that library.

On Fri, Mar 1, 2013 at 9:17 AM, Rob Eisenberg
rob@bluespireconsulting.comwrote:

I think it's generally best not to use viewAttached unless you really,
really have to. If it can be done in binding, then that's the way to go.
So, if I were using Kendo, I would plug into the binding hooks.

On Fri, Mar 1, 2013 at 4:26 AM, Rainer Wittmann notifications@github.comwrote:

Me too :).
@rgullhaug https://github.com/rgullhaug BTW There's another pattern
that would allow you to work with KendoUI widgets that doesn't requiere
usage of the beforeBindand afterBindhooks. If you'd ommit the
declarative declaration and configure widgets by using JavaScript you can
do something along the following line.
Within your view configure an element that will be converted to a Kendo
widget e.g.

.
Within your viewModel use the activate to accomplish setup tasks like
data retrieval e.g.

// Make sure too enable 'active : true' in the compose directiveactivate: function () {
// Grab some data as promise
system.log('ViewModel Activating', this);},...

Use viewModal viewAttachedto convert the dom element into a Kendo widget
e.g.

viewAttached: function (elem) {
// Resolve the promise and do something ...
system.log('Attached to elem', elem);
$(elem).find('.grid').kendoGrid(//kendo Widget configuration goes here);}

I have a prototpe of this pattern running here, but didn't test it
intensively. @EisenbergEffect https://github.com/EisenbergEffect Do
you see some pros/cons in this approach?

KendoUI released its 2013 beta lately and by glancing through their
documentation there seems to be a third option available as well (might be
available in the current version as well, but just stumbled over this
yesterday)..

http://docs.kendoui.com/howto/declarative_initialization#important-things-to-know

Kendo UI is not the only framework that uses data attributes for binding.
In fact, its pretty common. If you find yourself in a situation where you
need to mitigate collisions with Kendo UI and some other JS library, you
can provide a namespace for Kendo UI and then reference that namespace
instead.
kendo.ns="kendo";
// then data-bind="value: someValue"
// becomes data-kendo-bind="value: someValue"


Reply to this email directly or view it on GitHubhttps://github.com/BlueSpire/Durandal/issues/74#issuecomment-14279511
.

Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project
850.264.3996

Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project
850.264.3996

Contributor

RainerAtSpirit commented Mar 1, 2013

What is the reason for discouraging the use of viewAttached especially for third party components? I was under the impression that this would be the right hook that allows me to add (put your favorite JS library here) as at that point in time I can safely access the view's DOM element. Looks like I'm missing something.

Kendo's latest Beta adds TypeScript support, so I want to get a better understanding how to use TypeScript with Durandal before I move on.

Owner

EisenbergEffect commented Mar 1, 2013

It's better to build re-usable knockout binding handlers. This enforces a
stronger separation of concerns in your code and enables your modules to
function more like a true view model. In general you want to avoid view
code mixed with view model or model code as much as possible. viewAttached
is an important hook, since it's necessary to do more advanced things in
this way, where databinding breaks down. But, I would strongly encourage
looking at using ko binding handlers or durandal widgets to see if they
aren't a better solution in many cases.

On Fri, Mar 1, 2013 at 10:29 AM, Rainer Wittmann
notifications@github.comwrote:

What is the reason for discouraging the use of viewAttached especially
for third party components? I was under the impression that this would be
the right hook that allows me to add (put your favorite JS library here) as
at that point in time I can safely access the view's DOM element. Looks
like I'm missing something.

Kendo's latest Beta adds TypeScript support, so I want to get a better
understanding how to use TypeScript with Durandal before I move on.


Reply to this email directly or view it on GitHubhttps://github.com/BlueSpire/Durandal/issues/74#issuecomment-14294384
.

Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project
850.264.3996

Contributor

RainerAtSpirit commented Mar 1, 2013

I'll give the ko binding handler variant a shot as I've used them in the past. Need to dig deeper into durandal's widget to see how that would work. Thanks for the clarification!

I just wrote a blog post on how I have got Durandal and Kendo working fine together. You can read the post here:
http://rgullhaug.wordpress.com/2013/03/06/using-durandal-and-kendoui-together/

Thanks very much for the kendo UI solution. I was having exactly the same problem myself.

@breynolds breynolds referenced this issue in johnpapa/HotTowel Mar 10, 2013

Closed

Kendo UI Doesn't Integrate Well With Durandal #9

Does anyone have an example of a Durandal App using Kendo please? I am battling to understand where to call the application init (I am trying it in a test page)

    function activate()
    {
        var app = new kendo.mobile.Application($("#kendoindex"), {
            skin: "flat"
        });
    } 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment