Exclude html element at ko.applyBindings - javascript

Here is a simplified version of the problem:
<div id="model-one-container" data-bind="css: {foo: someModelOneProperty}">
<div id="model-two-container" data-bind="text: someModelTwoProperty"></div>
<div data-bind="text: anotherModelOneProperty"></div>
</div>
.
ko.applyBindings(viewModelOne, document.getElementById("model-one-container"));
ko.applyBindings(viewModelTwo, document.getElementById("model-two-container"));
If I do that, knockout will complain that there isn't a "someModelTwoProperty" in viewModelOne, so I need to exclude the #model-two-container div from the first applyBindings.
Is there any way to do this without altering the view-models?

Here's the answer.
Since knockout 2.0 there is a controlsDescendantBindings flag which you can use to create a custom binding that then stops KO from binding on an element or any of its children.

Related

knockout.js can you access the binding context from a script?

I have a javascript object graph, an HTML form, and knockout bindings connecting the two. The form is complex, and sometimes the form needs to add some computed observables to some sub-object in our object graph, and I want to do that locally in the the HTML element that has the data-bind which relies on this, I don't want such knowledge somewhere in some global script.
<div class="widget" data-bind="foreach: subThing">
<script type="text/javascript">
$data._scratchpad = ko.computedObservable( ... );
</script>
...
<input data-bind="value: _scratchpad"/>
...
</div>
Now in the context of this script, the binding context is of course not yet set up, so the $data property is not yet available.
But is there some event that I might put on the element or something so I can catch when the bindings are first initialized so I can add the necessary things before the actual data-bind expressions want to refer to them?
I came up with a solution which is just a little ugly, but actually practically correct. Instead of this script element above, I just use a virtual element that contains nothing and whose only point is to get an if: condition evaluated, where then we put the statements into the body of a function that gets evaluated:
<div class="widget" data-bind="foreach: subThing">
<!-- ko if: (function() { if(!$data._scratchpad) {
$data._scratchpad = ko.computedObservable( ... );
}})() --> <!-- /ko -->
...
<input data-bind="value: _scratchpad"/>
...
</div>
The nice thing is that required no modification of the source code. And while it is just a little ugly with the boiler-plate code:
<!-- ko if: (function() { if(!...) {
...
}})() --> <!-- /ko -->
I could potentially use a custom binding's preprocessor to wrap this function around and say instead simply:
<!-- ko setup:
...
--> <!-- /ko -->
this is almost neat, but really not so much better that it's worth it.
It's kind-a handy that this virtual element definition is already in a comment, so there won't be any worries with the javascript code using special characters.

How to properly code foreach and style binding

I have prepared a small jsfiddle here: http://jsfiddle.net/zb8jwre6/
Basically, I have observable array of sliders, and each slider should have it's own observable array of segments, which contain some properties for CSS-binding in HTML.
My first problem is that I'am not sure which foreach bind should i use:
This one doesn't work for some reason:
<div data-bind "foreach: $root.sliders">
<p data-bind="text: day"></p>
</div>
This one works, but I am not sure in which cases should I use this one:
<!-- ko foreach: sliders-->
<p data-bind="text: day"></p>
<!-- /ko -->
My second problem is that I don't know how to apply wanted CSS stylings from segment observable array.
I have tried this:
<div class='slider-segment' data-bind= "style: {left: segment_left, width:
segment_width, backgroundColor: segment_color}"></div>
But this does not work. I think I need to make those properties also as observables, but I am not sure how to do this properly in ViewModel
I would like to know what foreach binding should I use. When can I use "comment" foreach bindng and when do I use normal one, and I would like to know how to rework my code, so I can bind CSS properties from segments observable array.
Thank you!
I've changed
self.segments = ko.observableArray([segments]);
with
self.segments = ko.observableArray(segments);
See:
http://jsfiddle.net/x4a8pkmu/
I would like to know what foreach binding should I use. When can I use
"comment" foreach bindng and when do I use normal one, and I would
like to know how to rework my code, so I can bind CSS properties from
segments observable array
The "comment" syntax is useful if you do not want a container element. For example:
<ul>
<!-- ko foreach: myList -->
<li data-bind="text: myProp"></li>
<!-- /ko -->
</ul>
produces the same effects as:
<ul data-bind="foreach: myList">
<li data-bind="text: myProp"></li>
</ul>
The point of making a variable an observable is if you are going to change these values based on user interaction/server response, and then updating the UI. If the values are never going to change then using an observable for the style properties isn't helpful.
There is a very small difference between the two foreach loops - 'Comment' foreach does not have a parent div tag around the repeating child tags, while the other one does. So the outputs would look like:
Comment foreach:
<p>MON</p>
<p>TUE</p>
<p>WED</p>
Div foreach:
<div>
<p>MON</p>
<p>TUE</p>
<p>WED</p>
</div>
The comment foreach is useful for cases like these:
<ul>
<li class="header">Header item</li>
<!-- ko foreach: myItems -->
<li>Item <span data-bind="text: $data"></span></li>
<!-- /ko -->
</ul>

Angular JS ng-switch with ng-include?

I have 3 different code fragments which I'd like to swap out depending on the selection in a select menu.
It works if I include the code inline, but when I try to use ng-includes like this, I get an Angular error and the app fails:
<div ng-switch on="pFilter">
<div ng-include="'includes/parcel_details_incoming.html'" ng-switch-when="Incoming Parcels"></div>
<div ng-include="'includes/parcel_details_forward.html'" ng-switch-when="Exception Parcels"></div>
<div ng-include="'includes/parcel_details_exception.html'" ng-switch-default></div>
</div>
What am I doing wrong here? Does ng-switch not work with ng-includes?
The reason is both the directives ng-include and ng-switch-x use transclusion and you are specifying both on the same element and it is not allowed. Move nginclude to the child of ng-switch element.
<div ng-switch on="pFilter">
<div ng-switch-when="Incoming Parcels"><div ng-include="'includes/parcel_details_incoming.html'"></div></div>
<div ng-switch-when="Exception Parcels"><div ng-include="'includes/parcel_details_forward.html'"></div></div>
<div ng-switch-default><div ng-include="'includes/parcel_details_exception.html'"></div></div>
</div>
This used to work until angular 1.x version but compound transclusion will result in multidir error starting 1.2.x version of angular. Take a look at the change log and this commit.

Knockout 3.x: markup inside element referencing a named template is wiped out

In Knockout 2.x, one could write:
<div data-bind="template: { name: 'my-template', foreach: elements }">
<div class="placeholder"><- these are the array elements.</div>
</div>
This way, a placeholder element could be appended to the rendered elements.
But, as I see, Knockout 3.0 changed this behavior: "placeholder" markup is just wiped out of the container element.
Is this intentional? Any workarounds?
One solution that I can immediately think of is adding "afterRender" to the template definition, but this has (according to my experiments with KO 3.0) a weird glitch: it doesn't fire for empty "elements" array.
Thank you in advance for your answers.
In comparing similar usages of templates to that of using the foreach option, I could not get the placeholder markup to render except for the specific case identified. As such, I'd assume that might not have been an intended usage.
Since the foreach option to the template binding doesn't provide anything that can't be replicated, one option would be to move the elements into the data option of a regular template and then "manually" provide the foreach markup either within a "container" element or containerless.
Containerless option
<script type="text/html" id="containerless-regular-template">
<!-- ko foreach: $data -->
<div data-bind="text:$data"></div>
<!-- /ko -->
<div class="placeholder"><- these are the array elements.</div>
</script>
If you want to get a little more fancy due to more dynamic requirements for the "placeholder", you could nest another template call at the end of the foreach markup within a containerless if binding. The outermost container would be limited but the contents would be dynamic.
<script type="text/html" id="my-nested-template">
<!-- ko foreach: $data.foreach -->
<div data-bind="text:$data"></div>
<!-- /ko -->
<!-- ko if: $data.template -->
<div data-bind="template: { name: template.name, data: template.data }"></div>
<!--/ko -->
</script>
<div data-bind="template: { name: 'my-nested-template', data: {foreach: [], template: {name: 'another-template-name', data: {}}} }">
Fiddle

KnockoutJS animated transition

Can anyone explain why the animated transition example in the knockoutjs website here uses the template binding? The example uses this:
<div data-bind='template: { foreach: planetsToShow,
beforeRemove: hidePlanetElement,
afterAdd: showPlanetElement }'>
<div data-bind='attr: { "class": "planet " + type }, text: name'> </div>
</div>
But the following works just as well:
<div data-bind='foreach: {data: planetsToShow,
beforeRemove: hidePlanetElement,
afterAdd: showPlanetElement}'>
<div data-bind='attr: { "class": "planet " + type }, text: name'> </div>
</div>
Here is their original fiddle. Here is my updated fiddle. The use of the template binding seems extraneous. Thoughts?
There is no special reason why the sample uses the template binding.
On the top of the page it is even mentioned:
When using the template/foreach binding, you can provide afterAdd and beforeRemove callbacks.
So it does not matter whether you use the foreach binding or the template binding in "foreach mode", because internally the foreach binding just delegates back to the template binding.
So they are essentially doing the same thing only with different syntax, however you have more options if you are directly using the template binding:
The main difference is that when using the foreach binding you cannot use named templates you have to use the inline template, but the in template binding you can specify any template even change it dynamically.

Categories

Resources