0

I have a ViewModel which accepts JSON to build observableArray() and also have a selected observable for storing the object when editing.

var ViewModel = function (data) {
            var self = this;
            self.list = ko.observableArray(data);
            self.selected = ko.observable();
}

I'm showing the list in a table with edit button. On edit, the selected object goes into selected

self.edit = function (o) {
                self.selected = ko.observable(o);
}

Next, I have a form which binds with the selected and displays all the properties.

<form>
     <input type="text" data-bind="value: selected().Name">
</form>

The problem is that I want this form to be shown for adding an item and not only when the user clicks edit. But initially, the selected observable is undefined and throws error. Also, I want to push the data in selected to my observableArray when the user clicks on Add button.

What will be the best approach? Where can I put a custom binding so that this scenario works?

Update

My problem is similar this question. But I can't implement the given solution to an observable

Fiddle implementing a part of problem and a suggested solution

Community
  • 1
  • 1
CC7589
  • 133
  • 1
  • 12
  • If there is no selected item then the selected observable should not be used and there is no sensible value other than "doesn't exist". Use a ko-if to alter the template flow. If there is a selected item (i.e. for editing or whatever) then stub in an appropriate model as appropriate. – user2864740 Jun 16 '14 at 21:59
  • @user2864740 - I want to use the same form for create and edit. There is a selected item when an object is selected from the table for editing, but not when the form is used for creating a new object. Also, I don't want to have a ViewModel with hard coded properties since I have a huge number of properties. – CC7589 Jun 16 '14 at 22:04

3 Answers3

0
<form data-bind="with: selected">
     <input type="text" data-bind="value: Name">
</form>

This will not render the content of the form until a item is selected

To reuse form use a template binding

<form data-bind="template: { if: selected, data: selected, name: 'my-template' }">
</form>
Anders
  • 17,306
  • 10
  • 76
  • 144
0

Use a "blank" item in the selected variable to act as your "new item". Then, filling in the form for adding an item will fill in the values in the "blank" item.

Here are some snippets (partially based on your code and on another question)

Form:

<form data-bind="with: selected">
     <input type="text" data-bind="value: Name">
</form>

ViewModel

var ViewModel = function (data) {
            var self = this;
            self.list = ko.observableArray(data);
            self.selected = ko.observable(
                { name: "" });
}

Then, the "add" button for putting a new item into the data array can contain this:

// Add this item
self.list.push(self.selected());
// Reset the form to a new blank item
self.selected({ name: "" });

So when the form is loaded, there is an item in the selected variable - a blank item.


To avoid having to create a new blank model with all of the fields, you can use a variation on Ryan Niemeyer's answer here, using a valueWithInit binding for nonexistent fields. See his example jsFiddle.

Then, you can do this:

Form:

<form data-bind="with: selected">
     <input type="text" data-bind="valueWithInit: Name">
</form>

ViewModel

var ViewModel = function (data) {
            var self = this;
            self.list = ko.observableArray(data);
            self.selected = ko.observable({});
}
Community
  • 1
  • 1
Moshe Katz
  • 15,992
  • 7
  • 69
  • 116
  • I don't want to create a ViewModel with the properties defined as the actual list of properties is huge. – CC7589 Jun 16 '14 at 22:11
  • Please have a look at the [implementation](http://jsfiddle.net/JPYLp/70/) . Doesn't seem to be working – CC7589 Jun 17 '14 at 15:05
  • It works but I think the custom binding handler is only called once. So when I edit a record, the form doesn't populate. – CC7589 Jun 17 '14 at 15:42
0

Seems like just simple javascript was the answer to the question.

I added one Cancel button and on click of it:

document.getElementById("form").reset();

This also cleared the selected observable.

Also, for initial form display I used $data with all the properties:

<form data-bind="with: selected" id="form">
     <input type="text" data-bind="value: $data.Name">
</form>

No custom binding handlers were required!!

CC7589
  • 133
  • 1
  • 12