简体   繁体   中英

Performing jquery on knockout.js json data

I am trying to pull in a number from json using knockout.js and then using jquery to adjust my progress bar.

It works when manually entering the number into the html. It does not work when bringing in the number with json.

I am not sure if this is a conflict with knockout/json and jquery or if my code is wrong?

http://jsfiddle.net/infatti/5Q9pK/

// Knockout.js - bring in number of days from json
// -------------------------
// Here's my data model
var viewModel;
$.getJSON('http://echo.jsontest.com/daysDue/50', function (data) {
    viewModel = ko.mapping.fromJS(data);
    ko.applyBindings(viewModel);
});

// Progress Bar - adjust width of progress bar according to number of days
// -------------------------
$('#paging1 ul li').each(function () {
    // progress bar
    // find number of days until due date
    var progBarValue = $(this).find('.days-due').text();
    // limit days due to no more than 100%
    progBarValue = progBarValue > 100 ? 98 : progBarValue;
    // set progress bar width
    $(this).find('.bar').width((100 - progBarValue) +'%');

    // set class of progress bar for color based on days due
    if (progBarValue >= 75) {
       $(this).find('.progress').removeClass('progress-warning progress-danger').addClass('progress-success');
       $(this).find('.DueDate').removeClass('urgent');
    } else  if (progBarValue >= 25 && progBarValue <= 74) {
       $(this).find('.progress').removeClass('progress-success progress-danger').addClass('progress-warning');
       $(this).find('.DueDate').removeClass('urgent');
    } else if (progBarValue <= 24) {
       $(this).find('.progress').removeClass('progress-warning progress-success').addClass('progress-danger');
       $(this).find('.DueDate').addClass('urgent');
    }
});

You could do it this way. However, there is no point in loading your data in a knockout viewModel if you plan on manipulating the DOM with jQuery. Have you considered doing the following:

Use computed observables for width and class

var viewModel;
$.getJSON('http://echo.jsontest.com/daysDue/50', function (data) {
    viewModel = ko.mapping.fromJS(data);
    viewModel.progressBarWidth = ko.computed(function() { 
        return 100 - this.daysDue() + '%'
    }, this);
    viewModel.progressBarClass = ko.computed(function() {
        // note if (100 - x) >= 75, then x <= 25, etc.
        if (this.daysDue() <= 25) { return 'classa'; }
        else if (this.daysDue() > 25 && this.daysDue() <= 75) { return 'classb'; }
        else { return 'classc'; }
    ko.applyBindings(viewModel);
});

Now, you have a computed observables that compute the two values you're interested in, width and class.

DOM bindings and CSS

I'm not sure how your DOM is structured, but I'll take a guess.

<!-- container -->
<div data-bind="css: progressBarClass">
    <!-- progress bar -->
    <div class="progress" data-bind="style: { width: progressBarWidth }"></div>
    <!-- text -->
    <div class="DueDate" data-bind="text: daysDue"></div>
</div>

Then all that is left is to set up the classes in CSS to look to the parent for declaration. So for example, for the >= 75 days due case you could have:

.classa > .progress 
{
    // progress bar style, red or whatever
}
.classa .DueDate
{ 
    // text style, red or whatever
}

The answer by @MatthewJamesDavis is great, because it's a much cleaner way to tackle the situation.

However, the issue at hand and the actual question is probably why the jQuery text() function isn't finding the proper "50" that KO has bound to the span. The reason is that the getJSON method fires way later than the actual each that sets the progress bars. You can "solve" this by wrapping that bit in a function that's called at the proper time:

var viewModel;
$.getJSON('http://echo.jsontest.com/daysDue/50', function (data) {
    viewModel = ko.mapping.fromJS(data);
    ko.applyBindings(viewModel);
    updateProgressBars(); // NEW
});

function updateProgressBars() { // NEW
    $('#paging1 ul li').each(function () {
        // As before...
    });
} // NEW

Now, the progress bars are updated after you get your data with jQuery.

See this fiddle for a demo.

Again though, it's way better to bind the appropriate progress-bar attributes with KO instead of manually doing it with jQuery.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM