2

I'm using Knockout.js to wire up a dynamic form display. So instead of lovely named properties, I have an arbitrary number of "fields" in an array that I need to display and wire up. I think I'm close, but am failing in putting the finishing touches on my custom binding.

The Data

myDynamicFields = [
      {
        name: "email",
        value: "me@gmailllllll.com",
        type: "text",
        validation: {required: true},
        label: "Email Address",
      },
      {
        name: "username",
        value: "bobsmith",
        type: "text",
        validation: {required: true},
        label: "Username"
      }
  ];

I'm using ko.mapping to map this array to an observable array of observables. So not only is the entire array an observable, but each field such as "name" and "value" are also observables. This array should be able to have any number of elements and is keyed on "name".

My Custom Binding
The reason I need a custom binding (I think) is so that when something changes in my view, I can wire up which member of the array has changed. Again, it's keyed on name so I do a quick lookup. Check it:

ko.bindingHandlers.specialValue = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        model = _.find(viewModel, function (guy){
            return guy.name()==valueAccessor();
        });
        ko.bindingHandlers.value.init(element, model.value, allBindings, viewModel, bindingContext);
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        model = _.find(viewModel, function (guy){
            return guy.name()==valueAccessor();
        })
        ko.bindingHandlers.value.update(element, model.value, allBindings, viewModel, bindingContext);
    }
};

My Template
(Simply iterates through each element of my array)

{{#.}}
<p>{{label}}: <input data-bind='specialValue: "{{name}}", valueUpdate: "afterkeydown"'/></p>
{{/.}}

However, when I do this, nothing updates. I've gone deep into the Knockout code and found that a property called _ko_property_writers is not present on the allBindingsObject, but I'm out of my league as far as understanding of Knockout at this point.

user247702
  • 23,641
  • 15
  • 110
  • 157
matty-d
  • 2,623
  • 3
  • 18
  • 21
  • Well, how do you bind the value? – Eric Herlitz Feb 25 '14 at 18:09
  • @EricHerlitz I'm confused at your question. I'm making a custom binding that wraps an existing binding (ko.bindingHandlers.value) which hypothetically is sufficient to update the value on change – matty-d Feb 25 '14 at 18:13
  • I'm confused with what your are trying to update. From this it looks like you enter a name in an element then it finds a match, then you are trying to update that same element to the value property of the model. That seems awfully odd. if that is the case then you probably need something like element.value = ko.utils.unwrapObservable(valueAccessor()). otherwise i'm at a loss. – hubson bropa Feb 25 '14 at 18:25
  • 2
    I'm not sure why you would need a custom bindingHandler for this case. I wrote [a small jsfiddle sample using your myDynamicFields](http://jsfiddle.net/HD4F5/) which shows a way to bind these. If this is not what you want to do, perhaps you could elaborate further on your issue and perhaps also create a jsfiddle which shows your issue (what you have and what you want as output). – Robert Westerlund Feb 25 '14 at 19:58
  • @robert.westerlund did not realize that ko would keep track of which is which automatically. Thanks for your help! – matty-d Feb 26 '14 at 19:09
  • It sounds like you expect to have observable properties. This SO post might help you out. http://stackoverflow.com/a/10561681/2638872 – mrtig Mar 03 '14 at 00:37

1 Answers1

0

Presuming that you render this array to your HTML using the foreach binding, you're actually able to access your question model as the viewModel property in your binding (and most likely your root viewModel as $parent). You can read more on knockout's binding context here.

It does seem @robert.westerlund provided a nice solution in his JSFiddle, as well. And as that fiddle illustrates, it's worth adding that knockout also provides a $index variable within foreach loops, which can be a convenient help.

fredrikekelund
  • 2,007
  • 2
  • 21
  • 33