Knockoutjs: How can I pass a single item from an observable array into my viewmodel?

671 Views Asked by At

I'm creating a bug-handling program in KnockoutJS, and I've run into an issue. I have a list of "bug" reports on my main page that is displayed using an observable array. When I click "View" on one of the bug reports in the list, I have a Bootstrap modal pop up. I want to populate the contents of the modal with report details, but for some reason the viewmodel is not getting passed in correctly.

Here is my view model, along with my ajax mapping below that:

    function BugsViewModel(doJSON) { //doJSON determines whether to populate the observable with JSON or leave it empty
        var self = this;
        self.bugs = ko.observableArray();
        self.removeBug = function (bug) {
            $.ajax({
                url: "/ajax/getbugs.ashx?deleteBug=" + bug.Id()
            })
            self.bugs.remove(bug);
        }

        self.currentBug = ko.observable(); // <--this is the bug that I want to reference in the modal
        self.setModalBug = function (obj, event) { //obj is the individual array item
            self.currentBug = obj; //setting currentBug so that I can use it in my view
            alert(self.currentBug.Id()); //<--these alert properly, so I know that the value I'm passing in (obj) is correct
            alert(self.currentBug.BugName());
        }
        if(doJSON)
            getViewModelJSON(self.bugs); //this function loads my array (self.bugs) with observable items
    }
function getViewModelJSON(model) {
        $.ajax({
            url: "/ajax/getbugs.ashx"
        })
    .done(function (data) {
        ko.mapping.fromJSON(data, {}, model);
    });
    }

    $(document).ready(function () {
        viewModel = new BugsViewModel(true);
        ko.applyBindings(viewModel);
    });

I have my "View" button, which calls "setModalBug" and opens the modal:

<a href="#" class="btn btn-default" data-toggle="modal" data-target="#bugDetails" data-id="value: Id" data-bind="click: $root.setModalBug">View</a>

Then, inside my details modal, I have the textbox I want to populate with data. This is where I'm having the problem--currentBug.BugName is not populating the value correctly.

<input type="text" id="txtBugName" data-bind="textInput: currentBug.BugName" />

(Note that I am using the Mapping plugin for Knockout, so even though you don't see "BugName" defined in my viewmodal, it is being generated from the JSON when I call "ko.mapping.fromJSON()".)

I'm a little befuddled. Is this a runtime issue, or am I calling the viewmodel improperly? Or something entirely different?

Thanks

2

There are 2 best solutions below

4
On

You're not assigning your value to the observable correctly. You're doing:

self.currentBug = ko.observable();
self.currentBug = obj;

The first line creates an observable, but the second line throws it away and replacing it with the bug object. You want to assign to the observable, not throw it away, like:

self.currentBug = ko.observable();
self.setModalBug = function (obj, event) {
    self.currentBug(obj); //<-- Assign the current bug the currentBug observable
    alert(self.currentBug().Id()); //note the additional () to read the value of the observable
    alert(self.currentBug().BugName());
}
0
On

I got it working. Apparently in my code I actually didn't add the extra '()' to my alerts. Sorry--not my best moment. Now it works:

self.currentBug(obj);
alert(self.currentBug().Id());
alert(self.currentBug().BugName());

Then I added an extra '()' to my textInput data-bind:

<input type="text" id="txtBugName" data-bind="textInput: currentBug().BugName" />

I didn't realize that I had to use '()' anywhere on data-binds. I thought it figured out that you were working with observables and treated it that way (which it does on the property "BugName", but I had to access currentBug with '()' at the end).

Thanks, Retsam! I spent quite a lot of time on this and it was getting frustrating. Turns out it was a really simple fix.