1
votes

I have recently started playing with Knockout and I have hit a problem. I have tried Googling this in all sort of ways but I couldn't find any applicable results.

Let's say that I have this model:

var model = new function () {
    var that = this;

    this.parameterRegex = ko.observable(/\@@{1}\w+/ig);
    this.query = ko.observable('SELECT @@par1 from @@par2');
    this.parameterNames = ko.computed(function () {
        var allParameters = that.query().match(that.parameterRegex());
        return (allParameters == undefined) ? [] : jQuery.unique(allParameters);
    });
    this.parameters = ko.computed(function () {
        return ko.utils.arrayMap(that.parameterNames(), function (item) {
            return {
                Name: ko.observable(item),
                Example: ko.observable()
            }

        });
    });
};

In the HTML I am binding with the Parameters computed observable, but every time the Query observable changes and the Parameters observable recomputes, I lose all the state of the items in that computed.

What I mean by this is that if I bind a foreach in HTML with Parameters and I have some input boxes in that foreach, such as:

<textarea name="query" class="form-control" data-bind="value: query, valueUpdate:'afterkeydown'" rows="10" style="margin-bottom:20px"></textarea>
<div data-bind="foreach: parameters">
    <p data-bind="text: Name"></p>
    <input type="text"></input>
</div>

Any text that the user has typed in the input will be lost once the Computed Observeable is recalculated.

How would I go about solving this?

1
Is it possible for you to explain your code. Does the parameters array change at all? If it does what changes in it? The face that the text changes is the whole point of a computed function. If you don't want it to change then don't make it a computed. - Wayne Ellery
The parameters array changes according to the string query. This is split into an array of strings containing @@par1 and @@par2. As soon as you change the text in the string query, the computed will be recalculated - Christopher Demicoli
So what causes it to change? - Wayne Ellery
In my original post I have added a new textarea which is bound to the query. When this changes, the parameters will be recomputed - Christopher Demicoli
What do you want to happen if the text area is changed? - Wayne Ellery

1 Answers

1
votes

The solution is to keep a separate array with the objects in them and then re-use the objects if they exist in the array instead of re-creating them each time.

var parameters = [];
this.parameters = ko.computed(function () {
    var newParams = [];
    for (var i = 0; i < that.parameterNames().length; i++) {
        var name = that.parameterNames()[i];
        var result = $.grep(parameters, function(p){ return p.Name() == name; });
        var param;
        if (result.length === 0) {
            param = {
                Name: ko.observable(name),
                Example: ko.observable()
            };
        }
        else {
            param = result[0];
        }

        newParams.push(param);
    }
    parameters = newParams;
    return newParams;
});

jsfiddle