0

I'm trying to update UI when array propety is updated ,

I have array of colors , I trying to update the color red in colors array but it doesnot update the UI

var ViewModel = function() {
  this.self = this;

  self.colors = ko.observableArray([
    { color: "red", test: "aaa" },
    { color: "blue", test: "bbb" },
    { color: "yellow", test: "ccc" }
  ]);

  self.replaceIt = function() {
    const result = self.colors().filter(c => c.color === "red");
    result[0].color = "green";
    for (var i = 0; i < self.colors().length; i++) {
      self.colors.replace(self.colors()[0], result[0]);
    }
  };
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<ul data-bind="foreach: colors">
  <li>
    <span data-bind="text:color"></span>
    <span data-bind="text:test"></span>
  </li>
</ul>

<br/>
<br/>

<button data-bind="click:replaceIt">Replace It</button>

the result UI always display

red aaa
blue bbb
yellow ccc

but I want to update UI when I update property red to green

green aaa
blue bbb
yellow ccc

1 Answer 1

1

Since in your setup the color property is not observable itself,
you have to update the observableArray with a fully new array item in order to get the change tracking triggered.

self.colors.replace(result, { color: "green", test: result.test });

See working demo below.

 var ViewModel = function() {

    this.self = this;

    self.colors = ko.observableArray([
        {color: 'red' , test:"aaa"},
        {color: 'blue' , test:"bbb"},
        {color: 'yellow' , test:"ccc"}    
        ]);

    self.replaceIt = function() {

        const result = self.colors().filter(c => c.color ==="red")[0];
        if (result)    
        {   
            self.colors.replace(result, { color: "green", test: result.test });
        }
    };
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<ul data-bind="foreach: colors">
    <li>
    <span data-bind="text:color"></span>   
    <span data-bind="text:test"></span>

    </li>
</ul>
<br/>
<br/>

<button data-bind="click:replaceIt">Replace It</button>

Sign up to request clarification or add additional context in comments.

3 Comments

thank you @pfx for reply , but I was wondering if i have a big object like 30 property not only two as mentioned in the question and I want to update only one property , should I map all other 29 properties like you do in the answer, or should be a way to map them dynamically without writing them one by one
@ali I would make a viewmodel for the objects stored in the colors array, having an observable color property. Doing so, just changing the color to green updates the UI and you don't have to manipulate the array via the replace. Both solutions will work, it's a matter of preference.
@ali another possibility is to use ko.mapping to help with mapping/converting large dto's to knockout view models

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.