Getting the current 'foreach' item inside a context of 'with' binding - javascript

Suppose we have the following layout:
<tbody data-bind="foreach: items">
<tr>
<td data-bind="with: $parent.inplaceEditorVm">
<span data-bind="text: $parent.$data.OwnrPrefs"></span>
</td>
</tr>
</tbody>
How can we access the properties of the current foreach item in the context of the with binding?
I.E. In the example above, what do we need to write in a data-bind expression for the span element to get the value of the OwnrPrefs of the current foreach item?
When I'm using $parent.$data.OwnrPrefs like in the above example, it throws:
TypeError: Unable to get property 'OwnrPrefs' of undefined or null
reference
And when I'm trying to use $data.OwnrPrefs, the value of this expression is resolved to undefined, since the $data inside the scope of the with binding is the inplaceEditorVm object, not the current foreach item.

Bindings such as with and foreach create new binding contexts. The outer/original context, ie the one outside the with, is available as $parent - this is what $parent refers to, it's not (directly) related to your viewmodel structure, but rather the bindings on the page.
In your case, you can do:
<tbody data-bind="foreach: items">
<tr>
<td data-bind="with: $parent.inplaceEditorVm">
<span data-bind="text: $parent.OwnrPrefs"></span>
</td>
</tr>
</tbody>

Related

How to get a specific json value when ng-repeating twice?

I have a JSON object which is a parsed representation of a CSV file. I wanted to display it in a tabular format, so I used ng-repeat twice:
<table class="table left">
<tbody>
<tr ng-repeat="invoice in invoices track by $index">
<td ng-repeat="data in invoice track by $index">
<div class="cell" ng-class="{ 'no-dealer': !isDealer(data) }">{{ data }}</div>
</td>
</tr>
</tbody>
</table>
This gets me what I want. However, now based on a specific value (which is a unique code) in the JSON objects, I want to apply the no-dealer class on that specific tr/td (doesn't matter). How can I acheive this.
The data is like this
ng-repeat create a new scope, so for using the functions from parent scope you will have to use it like this -
ng-class="{ 'no-dealer': !$parent.$parent.isDealer(data) }"
Two times $parent to reach the main scope of page

Angular bind table to generic object

I'm just starting to explore with Angular. Now what I'm trying to do is using an mvc handler that returns a jsonobject. However the returned jsonobject is generic, so it can be different types of object, and they all have a different amount of columns. I want to bind all these columns to a table, but that means i can't just create a fixed amount of columns and bind them like so:
<table class="table">
<tr ng-repeat="r in items">
<td>{{r.ID}}</td>
<td>{{r.Name}}</td>
<td>{{r.FirstName}}</td>
<td>{{r.Telephone}}</td>
<td>{{r.Email}}</td>
</tr>
</table>
this is NOT the way i want it, basically i want to have a table that binds to an object and that creates table columns for every property of the object.
thanks for any advice!
You can iterate the properties of the value like
<tr ng-repeat="r in items">
<td ng-repeat="(key, value) in r">
{{ value }}
</td>
</tr>

ng-Show not updating inside ng-repeat

I have the following
<table id="socialMediaContainer" class="socialMediaContainer" style="width: 100%;">
<tbody>
<tr ng-repeat="row in detailCollection.ChannelsInfo"
ng-controller="WhiteLabelSitesCtrl">
<td><input id="txtSocialName" type="text" class="socialName"
placeholder="Name" ng-disabled="ViewMode" maxlength="250"
value="{{row.SocialChannelName}}" /> </td>
<td><input id="txtSocialURL" type="text" class="txtLabel socialURL"
placeholder="URL" ng-disabled="ViewMode" maxlength="250"
value="{{row.SocialChannelURL}}" />
</td>
<td class="DragnDropIcon"></td>
<td>
<a class="orange " ng-show="ViewMode">Upload</a></td>
</tr>
</tbody>
</table>
and I have another button outside the ng-repeat that updates the ViewMode variable, but this is not working inside the ng-repeat neither for the ng-show not the ng-disabled. what am i missing here?
The problem seems to be, that you need to move ngController directive to the table level (at least): it can't be on the same element with ngRepeat if the later iterated over the array defined in controller.
<table ng-controller="WhiteLabelSitesCtrl" ... >
<!-- ... -->
</table>
Demo: http://plnkr.co/edit/tu4TLmWIxdcYaiEd7whn?p=preview
ng-repeat creates a childscope for each item in the repeater.
Thus viewmode will be a primitive value on that child scope and therefore as a primitive will lose inheritance binding with the parent scope.
If you declare it as an object property in the controller scope however it will then be a reference to that parent object.
$scope.mode ={ViewMode: false}
html example
<a class="orange " ng-show="mode.ViewMode">Upload</a></td>
Try to pass object instead variable inside ng-repeat scope. Instead ViewMode,
declare in your controller:
$scope.model = {};
$scope.model.ViewMode = false;`.
And your binding must be like this: <a class="orange " ng-show="model.ViewMode">. After that all be work fine.
Read this article to understand why it happens: https://github.com/angular/angular.js/wiki/Understanding-Scopes
The button outside of the ng-repeat is not going to be nested in the same controller. The variable that it's modifying probably is not the same one that ViewMode under the WhiteLabelSitesCtrl is looking at.
When you point to this ng-controller, that controller will be activated with a new scope associated with it
<div ng-repeat ng-controller="WhiteLabelSitesCtrl">
<div ng-show="someValue"></div>
</div>
When you reference this controller again on another tag, it won't reference the existing controller as you might be expecting, it'll actually do the exact same thing... it will create the controller, and create a new scope for it- completely separate from the original one.
<div ng-controller="WhiteLabelSitesCtrl">
<button ng-click="someValue = !someValue"></button>
</div>

Knockout stops updating observable after unpacking property

Just noticed some unexpected behaviour in knockout.js - Got some code that loops round an observableArray and repeats some bound HTML elements for each item in the array. One of the items is a property on a sub-object:
<tbody data-bind="foreach: Contact">
<tr>
<td data-bind="text: Name"></td>
<td data-bind="text: Project().Name"></td>
<td data-bind="text: Percentage"></td>
</tr>
</tbody>
This renders fine on page load. But if the user performs actions that end up changing the Contact array or the items inside it, Name and Project().Name update but Percentage does not, even though stepping through shows it has the correct value.
However, if I remove the unpacked sub-object:
<tbody data-bind="foreach: Contact">
<tr>
<td data-bind="text: Name"></td>
<td></td>
<td data-bind="text: Percentage"></td>
</tr>
</tbody>
Everything works perfectly.
What's going on here, and is there a fix better than using a computed observable or somesuch to calculate and hold my Project().Name value?
try this
<td data-bind="text: ko.computed(function() { return Project().Name() })"></td>
if you need 2-way binding, you can use writable computed

Knockout JS foreach looping through array of objects

I have a observableArray:
self.stats = ko.observableArray([
{"DFTD" : new Stat("Defensive TD", "DFTD",0,20,0,self.playerGroups[1])},
{"GL" : new Stat("Games Lost", "GL",0,16,0,self.playerGroups[2])},
{"FGA" : new Stat("Field Goals ATT", "FGA",0,100,0,self.playerGroups[0])},
]);
and i am trying to loop around it with a foreach and then print out the Stat objects name property which is the first element in that object.
<tbody data-bind="foreach: stats" id="stat-sliders">
<tr>
<td><span data-bind="text: stats.Stat().name"></span></td>
<!--/*<td class="statsListItem">
</tr>
</tbody>
Im not sure if im doing it right. I am a beginner with knockout and wondering if anyone can help?
The fiddle below creates an array of football stats, which contains a key field and a stat field. You could use the key field for quicker access if you like. If you want an object where you have the property be the key, that would allow for the quickest indexing, though its not an array then.
See if this is what you want.
http://jsfiddle.net/johnpapa/CgFjJ/
You shouldn't need to call back into stats. Notice that the span binds to the property of the model that is inside the array.
<tbody data-bind="foreach: stats" id="stat-sliders">
<tr>
<td><span data-bind="text: name"></span></td>
<!--/*<td class="statsListItem">
</tr>
</tbody>
Also, I don't think Knockout works well with keyed arrays like that.

Categories