Terje Nygård
Terje Nygård

Reputation: 1257

Knockout.js - UI not updated after observable has been set / changed

I'm having a list, displaying photo-thumbs When clicking a thumb, a bootstrap modal is opened, displaying the clicked thumb as a fullscreen image. This is done by updating an observable().

problem is.. UI's not updating, resulting in no data displayed, no image or text. Modal popup functionality is working properly.

BUT.. when console.logging the observable. It displays the object as it should, and is updated.

So why does this seem fine when i'm console.logging it, and not in the UI ?

Click event (inside foreach)

<a data-toggle="modal" data-target="#full-modal-photopage" data-bind="click: $parent.setSelectedPhoto">
    <img data-bind="attr:{src: BlobUrlPhotoThumb}" style="max-width: 100%; max-height: 100%;" />
</a>

Modal to display selected photo (bootstrap modal)

<div class="modal fade" id="full-modal-photopage" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="z-index: 999999999999">
              <div class="modal-dialog">
                <div class="modal-content">
                  <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                    <h4 id="myModalLabel" data-bind="text: selectedPhoto.PhotoText "></h4>
                  </div>
                  <div class="modal-body">
                    <img data-bind="attr: { src: selectedPhoto.BlobUrlPhoto }" id="full-modal-img" alt="" />
                  </div>
                  <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-primary">Save changes</button>
                  </div>
                </div>
              </div>
            </div>

Observable init & setSelectedPhoto script

self.selectedPhoto = ko.observable();

    self.setSelectedPhoto = function(selPhoto) {
        self.selectedPhoto(selPhoto);
        console.log(self.selectedPhoto());
    }

Screenshot of console.log enter image description here

Upvotes: 1

Views: 914

Answers (2)

Tomalak
Tomalak

Reputation: 338208

Observables are functions. You can use them directly as event handlers in knockout, an extra setSelectedPhoto() method is superfluous:

<a data-bind="click: $parent.selectedPhoto" data-toggle="modal" data-target="#full-modal-photopage">
    <img data-bind="attr:{ src: BlobUrlPhotoThumb}" style="max-width: 100%; max-height: 100%;" />
</a>

Now selectedPhoto will be updated on click.

In your modal you can use with: selectedPhoto to a) rebuild the inner part when selectedPhoto changes and b) set a context for the properties you are referring to:

<div class="modal fade" id="full-modal-photopage" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="z-index: 999999999999">
  <div class="modal-dialog">
    <div class="modal-content" data-bind="with: selectedPhoto">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h4 id="myModalLabel" data-bind="text: PhotoText"></h4>
      </div>
      <div class="modal-body">
        <img data-bind="attr: { src: BlobUrlPhoto }" id="full-modal-img" alt="" />
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

With this kind of setup it's not relevant whether BlobUrlPhoto or PhotoText are themselves observables or not. The with binding does the right thing.

Upvotes: 1

Rango
Rango

Reputation: 3907

Since your selectedPhoto is observable you have to add parenthesis before accessing observable's properties:

<h4 id="myModalLabel" data-bind="text: selectedPhoto().PhotoText "></h4>
...
<img data-bind="attr: { src: selectedPhoto().BlobUrlPhoto }" id="full-modal-img" alt="" />

Update:

Another way you may prefer is using with binding that sets binding context to given variable (either plain or observable). So add it to #full-modal-photopage:

 <div class="modal fade" id="full-modal-photopage" data-bind="with: selectedPhoto" ...

and access properties without specifying selectedPhoto:

<h4 id="myModalLabel" data-bind="text: PhotoText "></h4>
...
<img data-bind="attr: { src: BlobUrlPhoto }" id="full-modal-img" alt="" />

Upvotes: 2

Related Questions