knockout view model wrapped in observable - view

To avoid calling applyBindings multiple times on the same DOM element, I wrap my various viewmodels in an observable. then just change that observable to whatever view model i wanna see and BAM...that works.
until i do something like this:
<div data-bind="if:$data">
...some bindings in here
</div>
when i change view models, the bindings inside any "if:$data" blocks do not update.
here's a fiddle to really demonstrate this: http://jsfiddle.net/btrauma8/2TxME/

This would have worked properly prior to KO 2.2. In 2.2, we made if and ifnot more efficient by only re-rendering the section when the value actually changes between truthy/falsy.
There were many cases where people would bind against something like if: items().length and the entire section would be re-rendered everytime that an item was added.
In your case, you can overcome this pretty easily by just using the with binding instead of if. Since, you are binding against $data, it will not actually change the context and will give you the result that you are after.

Related

Knockout - Disabling the default behavior of updating model when using binding value with form element

Knockout has the default behavior of updating the associated model if you change your focus (e.g. by clicking outside the input control) after editing the value inside an input control, populated by a binding of type Value.
Here is the link to the official documentation page explanation, section Parameters:
http://knockoutjs.com/documentation/value-binding.html
Do you know a way to disable this default behavior ?
The reason behind this : Im using Models that can tell if their last update requires persistent backup by comparing the previous value to the new one.
I would like to listen to the key up event on my form inputs but if I do that, knockout triggers twice event (the default one + the key up) to update the Model and the second one is basically telling my Model to replace the value by the same value because it is already updated, which it translates to "there is no need to do persistent backup since the value didnt change".
I would gladly appreciate any help or suggestion, since Im stuck and can't find a way around :)
EDIT
Couldnt reproduce the error with bare backbone code. It seems as "super cool" said that valueUpdate should override the default Blur event that triggers when you use form controls with binding Value.
It may be a bug introduced by the library Knockback that I use to create the ViewModel.
Despite all this, just replacing the binding Value by the binding textInput did the trick. Thank you all.
Don't listen to the event, subscribe to updates, which won't fire unless the value is changed. Using the textInput binding will register every change to the value, even those done using menu items like cut and paste, when they happen.
Equivalently, you can use the value binding along with valueUpdate: 'input'
vm = {
myvar: ko.observable(),
updates: ko.observableArray()
};
vm.myvar.subscribe(function(newValue) {
vm.updates.push(newValue);
});
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="textInput: myvar" />
<div data-bind="foreach: updates">
<div data-bind="text: $data"></div>
</div>

Ember.js and Isotope.js - Executing Javascript after all childviews became rendered

I use Ember.js (1.0. RC) and would like to apply Isotope.js's functionality to some of my views located in a "container".
So my route basically loads the models containing the needed data from a server, sets up the controller's content and binds it to the model's data, which works fine.
Next I declared a template for my IndexRoute which iterates over all the loaded items like this:
{{each item in this itemViewClass="App.ItemView"}}
The items are the images that should be filtered with isotope.js. ItemView only refers to a simple template for the time being.
The execution chain is the following: Route -> Fetching model data -> Set up controllers -> Create IndexView -> Pile up all the ItemViews in a DIV-container.
Now I need to check whether all the ItemViews are loaded and the rendering is finally finished to apply isotope.js's filtering functionality but I can't figure out how to do that.
The didInsertElement of the IndexView event fires as soon as it's been rendered and before the ItemViews were added to the DOM.
I already tried to set up a ContainerView which would work in conjunction with Ember.run.scheduleOnce("afterRender"...) if I didn't fetch the data through the models but hardcoded it to the content variable.
The CollectionView also did me no favor with this exercise.
Any ideas how to solve that misery? I'd really appreciate it. Thanks.
I am not sure how exactly isotope.js works..considering its just a jquery plugin, you can call isotope like this even if it is a ContainerView or CollectionView.
didInsertElement: function() {
Ember.run.next(this, function(){
this.$().isotope({}) // or watever code u want to write
});
}
This makes sure that the code inside ember.run runs once rendering is done completely..

Rendering collection view in CompositeView triggered constructor?

I have a composite view which has a task, and it's comments. I put it onto a contentRegion to display. When rendering model alone, it works fine. However when come to collection, it behaves really strange. console.log shows initialize function has been triggered twice. The first time is when define the view
taskView = new MyProject.Views.Task
model : task
collection : comments
I then do a MyProject.contentRegion.show(taskView) in order to render the model view. After that, I just call comments.fetch() to get all the comments. Then comes the problem, it re-initialized my taskView and the template keep complaining xxx is undefined.
Any thoughts? I know it's weird because another CompositeView in my project works great.
NathanInMac, I've done a little testing from your suggestion of using an itemView and found some interesting stuff.
Was your problem involving nested compositeviews'? As mine was but I'm unsure if that affects anything.
What solved the problem was initially trying a collectionView which couldn't find the itemView so I moved the definition of the itemView for the collectionView/compositeView to before the definition of the collectionView(or extended).
This seems to be a working fix and just a misleading bug with compositeView's double initializing instead of displaying some exception or error.

Performance issue in backbone template

I am having a performance issue with backbone template.
The situation is I have collection of model, each model have a field called 'isSelected'.
I need to render this collection with a template for each individual model. The 'isSelected' field is used for setting the checkbox in the template.
For the sake of discussion, the template is as following.
<div class='thumbnail'>
<input class='checkbox' type='checkbox' {[ if (isSelected) { ]} checked='checked'{[ } ]}
</div>
When I need to make the checkbox all selected, I will update the field to true for each model in the collection.
The code I used is
this.collection.each(function(e) {
e.set("isSelected", true);
});
However, this way is very slow, for a collection contains 25 items, it will take almost 10 sec to make all checkbox 'checked'.
I am expecting that it should least than 1 sec, if i use plain jquery.
Is there any problems with this approach? what's the best approach for this kind problem?
Why don't you set isSelected to true as default in the model? That way you don't have to loop through the collection to set each of them to true.
It's hard to tell what's taking up all the processing time with the amount of code you posted. My first guess would be the render function is being called multiple times. Creating and destroying templates kills performance. If you hard more code posted it might be easy to spot any problem areas.
You should render all of the HTML nodes that could possibility be need. After they are rendered save a jquery selector and use that to toggle the selected.
Most of the time it isn't JS or Backbone that is the bottleneck. It's that JavaScript is triggering the DOM, CSS or reflows constituently and the browser is doing way too much work.
I'm building a PerfView for for backbone. It can render a collection with 1,000,000 models and scroll at 120FPS on chrome. The code is on Github at: https://github.com/puppybits/BackboneJS-PerfView. There's a lot of optimizations in there and comments in the code. One of the techniques in there is sure to solve your issue.

Refreshing Partial View in MVC 3

I have a partial view that I have included on my _Layout.cshtml. It simply has a javascript function that changes an image based on the state of my system. I don't need to reload any data, I don't need to go to the code of the controller for anything, I simply need to reload that partial view.
I tried many of the examples that I found here but couldn't get any of them to work. I felt as if they were too complex for what I was doing anyway. Any guidance would be appreciated.
Thanks,
Steve
If the partial is loaded into the layout directly then there's no straightforward way to refresh it, because it's basically a part of the complete rendered page.
Your best bet is to render the partial using $.load or whatever equivalent you have available by hitting a controller method and rendering the result into a container (like a div). You would have to do this within a script that is loaded with the layout itself, by observing document.ready or something like that. Once you have that in place then it's trivial to keep reloading or refreshing the contents by hitting the controller method as many times as you need. For example in jQuery:
$(document).ready(function () {
RefreshPartial();
window.setInterval(RefreshPartial, 10000);
});
function RefreshPartial() {
$('#container').load('/some/controller/endpoint', {parameters});
}
This will call the controller method, and set the inner contents of the element identified with #container. You can call RefreshPartial as many times as you want.
Partial views only exist on the server. The only way to "refresh" the partial is to go back to the server to get it again.
Obviously, you must be doing something in the partial that needs refreshing. Whatever that is, should be callable from javascript to do the refresh.

Resources