1

Problem: I am creating an element via a JS templating system. Inside that template I am specifying an ID. After that ID is created, Is there a way with jQuery to fire a callback when a specific element is created?

Example JS/HTML with Knockoutjs:

function Dialogs(){
    this.createDialog = function(id){
        //alert('creating dialog');
        // If i add a setTimeout here, it will work.
            $("#" + id).dialog({
                autoOpen: true,
                resizable: false,
                width: 360,
                height: 200,
                dialogClass: 'systemError',
                modal: true,
                closeText: 'hide'
            });


    };
    this.data = ko.observableArray([
        new Dialog("Demo", 'htmlContent', { 
            id: 'testDialog',
            success: function() {}, 
            error: function(){},
            actions:[
                new DialogAction('continue', { 
                    className: 'foo', 
                    id: 'bar',
                    events: { 
                        click: function() { 
                            console.log('do stuff');
                        }
                    }
                })
            ] 
        })

    ]);
}
function Dialog (name, htmlContent, options) {
    options = options || {};
    this.id = options['id'] || '';
    this.name = ko.observable(name || "");
    this.className = options['className'] || '';
    this.htmlContent = ko.observable( htmlContent || "");
    this.successCallback = options['success'] || this.close;
    this.errorCallback = options['error'] || this.throwError
    this.actions = options['actions'] || [];
}

function DialogAction (name, options) {
    options = options || {};
    this.name = ko.observable(name || "");
    this.className = options['className'] || null;
    this.id = options['id'] || null;
    this.successCallback = options['success'] || null;
    this.errorCallback=  options['error'] || null;

}
ko.applyBindings(new Dialogs());

The HTML:

<div id="dialog-holder" data-bind="foreach: Dialogs.data()">
      <div class="systemErrorDialog" data-bind="template: { name: 'dialog-system-error', data: $data, afterRender: Global.Dialogs.createDialog($data.id) }"></div>
</div>

<script type="text/template" id="dialog-system-error">
    <div data-bind="html:htmlContent(), attr:{id: id, class:className,title:name()}">
      <div class="actions" data-bind="foreach: actions"> 
        <div data-bind="attr:{id: name(), class: className}"></div>
      </div> 
    </div>
</script>
Fostah
  • 2,947
  • 4
  • 56
  • 78
  • A code sample would be great. – EasyCo Nov 14 '12 at 22:49
  • 1
    You could bind to dom mutation events, though it would probably be better to just run your code or trigger an event after the html is created and appended by the template. – Kevin B Nov 14 '12 at 22:51
  • How is the element being created? – David G Nov 14 '12 at 22:52
  • 1
    Templating system like Mustache or Handlebars? I don't really see why you need a callback to be honest. The element will be created after the template adds it's content into the DOM. Add your logic there, or trigger your own event that you can listen for. – asgeo1 Nov 14 '12 at 22:54
  • Just attached the code, It is firing the afterRender function, yet the length of the element is still 0 – Fostah Nov 14 '12 at 23:02
  • Did you try binding to `afterAdd()`? – nrodic Nov 14 '12 at 23:15
  • Your success callback is empty `success: function() {},` – chovy Nov 14 '12 at 23:16

1 Answers1

1

You could run an interval to check for the id in the dom, and then fire an event if it exists.

var intv = setInterval(function(){
 var $el = $("#myId");

 if ( $el.length > 0 ) {
   clearInterval(intv);
   doSomething();
 }
}, 500);

probably should clear the interval after 10 secs in the event if never shows:

setTimeout(function(){
  clearInterval(intv);
}, 10000);
chovy
  • 72,281
  • 52
  • 227
  • 295
  • I didn't downvote, but why should we have a recurring setTimeOut to run for all the time the element does *not* exists? – David G Nov 14 '12 at 22:55
  • @David Maybe OP was about firing callback and target platform is not guaranteed to support dom mutation events? – nrodic Nov 14 '12 at 22:56
  • This would be an acceptable answer, but, I was looking for any native jQuery funtionality like .done() or .promise() if it exists. – Fostah Nov 14 '12 at 22:58
  • i agree its not ideal, but without a code example...i cleared it after 10 secs. – chovy Nov 14 '12 at 22:58
  • @fostah, if it's an ajax call you should be handling it in the callback. – chovy Nov 14 '12 at 23:01
  • @chovy It's not a ajax call, and I am using the afterRender callback, however for some reason the node does not exist still. If i add a setTimeout it works. But I was trying to avoid if possible. – Fostah Nov 14 '12 at 23:09
  • 1
    @Fostah The only jQuery solution would be livequery, but all that does is listen to dom mutation events if available, or the setInterval provided in this answer otherwise; both of which can be inefficient solutions compared to instead reacting to the code that generates it informing you that it was generated. – Kevin B Nov 14 '12 at 23:09