Bindings are not working after jquery .html() appe

2019-05-18 03:29发布

问题:

I have this simple div:

<div id="mainContent">

</div>

and it's empty. Now I'm trying to append this HTML to the above div:

<div id="mainContent">
   <label>Project Name</label>
   <input type="text" id="projectName" data-bind="value: projectName"/> 
   <label>Tracker Name</label>
   <input type="text" id="trackerName" data-bind="value: trackerName"/>
</div>
<button type="submit" data-bind="click: submitNewProject">Submit</button>

By using:

                       $.ajax({
                             type : 'POST',
                             url : 'newTracker.php',
                             dataType : 'html',
                             success : function(data){
                                     $("#mainContent").html(data);
                             },
                             error : function(XMLHttpRequest, textStatus, errorThrown) {
                                     alert('Something is wrong!');
                             }
                     });

Where data is the HTML I'm trying to assign by: $("#mainContent").html(data);

At first look everything looks pretty, but there is a problem - the bindings are not working.

What I mean is that in the newly assigned HTML I have a button supposed to call a viewmodel function, but it does not...

BUT if I place the code directly inside of the div the bindings are working like a charm.

Why my bidings are not working when I'm assigning a new HTML code inside of the div? I know that I'm missing something really small and basic here, but I can't spot it.

EDIT:

Button event:

 submitNewProject = function(){
                            console.log("submit new project");
                        };

回答1:

Knockout cannot track newly created elements, if your DOM changed using Ajax methods you'll have to explicitly bind a view-model to the newly created elements.

Something like:

$.ajax({
    type: 'POST',
    url: 'newTracker.php',
    dataType: 'html',
    success: function (data) {
        var $mainContent = $("#mainContent");
        $mainContent.html(data);

        var existingViewModel = ko.dataFor(document.body);
        ko.applyBindings(existingViewModel, $mainContent.get(0));
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
        alert('Something is wrong!');
    }
});


回答2:

As most have pointed out. When you add the HTML dynamically with the append, the DOM isn't reevaluating the bindings. So, you need to either:

  1. apply/reapply your bindings in the .ajax success event handler
  2. apply/reapply your bindings in a document html onChange handler
  3. place your HTML statically in the first place but use a class for all the elements that has a style of set the display:none, then change the style to display:block, display:inline-block, etc..
  4. use a hybrid of above with some static HTML to at least establish the binding between the button and function and anything else that will be required to make the bindings work, but then dynamically .append() anything else that is not dependent on the binding


回答3:

Sometimes you need to create a secondary function on the parent page to apply the bindings and then call that function from within the appended text. All the functions defined on the original page as it loads will be available. I have used this method before, though you have to know in advance what functions you will need to build. Or you can just include the binding as part of the post-ajax process.

It makes ajax loads with decent functionality

function bindStuff() {
    $(".class1").click(function() {
        // do something with the bind        
    });
}
function ajaxLoad() {
    // Perform ajax load
    // on complete call your bindings
    complete: function() {
        bindStuff();
    }
}

With your example:

                  $.ajax({
                         type : 'POST',
                         url : 'newTracker.php',
                         dataType : 'html',
                         success : function(data){
                                 $("#mainContent").html(data);
                         },
                         complete: function(){
                                 bindStuff();
                         },
                         error : function(XMLHttpRequest, textStatus, errorThrown) {
                                 alert('Something is wrong!');
                         }
                 });