arturadib / agility

Javascript MVC for the "write less, do more" programmer
http://agilityjs.com
MIT License
542 stars 70 forks source link

Feature Request: Event after model is ready #52

Open phonovision opened 13 years ago

phonovision commented 13 years ago

When the "create" event is fired the model seems to be not accessible yet. Some sort of "afterCreate" event would be useful in some cases.

I worked around this using a jQuery callback:

// [...]
controller:
            { 'create': function() {
                    //model not ready yet
                    //trigger jQuery-Callback $(...) when ready
                    that = this;
                    $(function() { that.trigger('change'); });
              },
              'change': function() {
                  ...
                                  ...
              } 
            }
phonovision commented 13 years ago

This could be related to #50

tristanls commented 13 years ago

I don't think it's documented yet, but the "afterCreate" event you're looking for is "post:create".

[...]
controller: {
  'create': function() {
    // create code
  },
  'post:create': function() {
    // "afterCreate" code
  }
}

Let me know if that meets your needs. ( the pull request implementing the feature is documented in #46 )

Cheers,

Tristan

phonovision commented 13 years ago

Hi Tristan, thanks for your answer!

"post:append' seems to nearly fit my needs. The model is ready but the controller doesn't wait until DOM ready. This can be solved (or worked around?) by using a jQuery callback:

//example: part of my jQuery-UI Tabs implementation
var tabContainer = $$({
    model:  { id:       'placeholder_tabcontainername'},
    view:   { format:   '<div data-bind="id id"><ul/></div>'},
    controller:
            { 'post:append': function() {  //bind jquery-ui tabs to div
                                        var tab = this.view.$();
                                        $(function () { tab.tabs(); });
              } 
            }
});

Although I would prefer not to delegate the "action" to a jQuery callback this is nicer and less hacky than my already mentioned work-around.

If you don't have a hint for a better solution you can close this issue. I'm satisfied with this solution. Thank you very much!

tristanls commented 13 years ago

Hmm...

I am curious because I was having a similar DOM related problem. Are you appending the tabContainer to $$.document later on, or are you appending it to some other widget, say: widget, which then itself is appended to $$.document? Something like:

var tabContainer = $$( ... );
var widget = $$( ... );
widget.append( tabContainer ); // will fire 'post:append'
$$.document.append( widget ); // will only fire 'post:append' on widget and not tabContainer

If the above is the case, then a possible solution could be some sort of propagation of the pre and post appended hooks, but I'm not clear how that would be done yet because we'd need to be able to tell the difference when it's appended to the DOM v. another agility object.

Having said that, the jQuery callback seems like a very useful workaround.

phonovision commented 13 years ago

Sorry if this example is a bit lengthy...

The MVC part:

// Tabs -----------------------------------------------------------------------
var tabContent = $$(    {   id:     'placeholder_id', content:'' }, 
                        '<div data-bind="content, id id"/>' );
var tab = $$({    //Tab header
    model:  { caption:  'placeholder_caption',
              ref:      'id_placeholder' },
    view:   { format:   '<li><a data-bind="caption, href ref"/></li>'}
});
var tabContainer = $$({
    model:  { id:       'placeholder_tabcontainername'},
    view:   { format:   '<div data-bind="id id"><ul/></div>'},
    controller:
            {  'post:append': function() {  //bind jquery-ui tabs to div
                                        var tab = this.view.$();
                                        $(function () { tab.tabs(); });
              } 
            }
});

Yes, the tabContainer is appended to an widget ( just a simple div container without special functionality till now). My usage:

// Container
tabs    = $$(tabContainer, {id:"tabs"});
aView.append(tabs);
// Header
tabA    = $$(tab, {caption:'Tab A', ref:'#tabA'});
tabB    = $$(tab, {caption:'Tab B', ref:'#tabB'});
tabs.append(tabA, 'ul');
tabs.append(tabB, 'ul');
// Content
tabAContent = $$(tabContent, {id:'tabA', content:'Just some simple text'});
tabBContent = $$(tabContent, {id:'tabB'}); //content retrieved by AJAX later on
tabs.append(tabAContent);
tabs.append(tabBContent);

Maybe the jQuery-UI Tabs are not the best example as they are a bit more complex and an "add"-method exists. But the "add"-method seems to do no magic and it is not available for an accordion for example.

tristanls commented 13 years ago

Thank you @6triple8 for the specific example. That seems to me to reinforce how the append is being fired currently and how it causes what you're seeing and having to rely on jQuery callback. Let's leave this open for now because it would be nice not to have to reach outside the framework for DOM-ready-dependent code.

phonovision commented 13 years ago

Yes, I agree with that. The workaround is usable but as it is somehow a "break" in the concept/encapsulation of agility it's more a fallback than a real solution.

If there is a better solution this would be great. Especially as there are probably some more users experiencing similar problems.