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>
Related
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>
I'm under the impression that ng-repeat creates a new scope for each element in the array/object.
Is it possible to access these new scopes that the ng-repeat creates from the controller? For example if you know the index?
Any help would be much appreciated.
Check the console of this demo: JSFiddle.
console.log the scope, there are two attributes $$childHead and $$childTail. They are the first and last child scopes created by ng-repeat.
After getting the first child scope $$childHead, you can traverse to get other ng-repeat scope objects through $$nextSibling and $$prevSibling.
Note: these attributes start with $$, which indicate that they are private Angular variables. I suppose they are not intended to be used directly.
If you use ng-repeat like <div ng-repeat="item in items"></div>, you can use ng-click="dealWithItem(item, $index)" to pass this item to a function defined in the controller:
$scope.dealWithItem = function (item, index) {
// console.log(item);
}
It works for nested ng-repeat as well: JSFiddle.
When I tried Joy's answer, I got undefined for the item variable at the console. But there is an easier way to do it.
html:
<tr ng-repeat="name in names">
<button class="btn btn-info btn-sm pull-right" ng-click="dealWithItem()">{{name.first_name}}</button>
</tr>
Controller:
$scope.dealWithItem = function () {
console.log(this.name.first_name);
}
this.name will have all of the attributes associated with $scope.names.
You can use $parent as an argument of your function to access these scopes:
<div ng-repeat="item in items">
<div ng-click="doSomethingWithItem(item, $parent)"></div>
</div>
I have a ng-click nested inside a ng-repeat, and I am trying to pass a value from the current item in the loop. If I inspect the html generated using Chrome developer tools it looks correct (&ID=1) but when I put a break point in the function it shows &ID={{d.ID}} as the value that gets passed to the function.
Any help is appreciated.
<tr ng-repeat-start="d in data">
</td>
<td>
{{d.OrganizationName}}
</td>
</tr>
Try it:
<tr ng-repeat-start="d in data">
</td>
<td>
<a href="" ng-click="openDialog(false,'http://portal.sharepoint.com/Lists/Organization/DispForm.aspx?IsDlg=1&ID='
+d.ID)"> {{d.OrganizationName}}</a>
</td>
</tr>
I would recommend passing the Id in as an attribute of the openDialog method and building the url string in the controller.
ng-click="openDialog(false,'http://portal.sharepoint.com/Lists/Organization/DispForm.aspx?IsDlg=1', d.ID)"
then build the string in the controller and perform your location change. Easier to debug and un-clutters the view.
you could also store this string in your controller 'http://portal.sharepoint.com/Lists/Organization/DispForm.aspx?IsDlg=1'
ng-click="openDialog(false, d.ID)"
ngClick directive will evaluate an expression. I guess it's not what you want
Try to change ng-click by simple onclick. It will solve your problem:
Change
{{d.OrganizationName}}
for
{{d.OrganizationName}}
With ng-click. you don't need to use {{}} in order to get the variable value. Like in this sample from Angular Docs
<button ng-click="count = count + 1" ng-init="count=0">
Increment
</button>
<span>
count: {{count}}
</span>
I have an html table, <tbody> of it is generated with angular ng-repeat. Here is my html:
<tbody>
<tr ng-repeat-start="car in carList | filter:tableFilter" ng-click="activeRow = car.name">
<td><a target="_blank" href="{{car.carLink}}">{{car.name}}</a></td>
<td>{{car.review}}</td>
<td>{{car.rating}}</td>
<td>{{car.fiveStarPercent}}</td>
<td>{{car.recommended}}</td>
<td>{{car.price}}</td>
</tr>
<tr ng-repeat-end ng-show="activeRow==car.name">
<td>{{car.name}}</td>
</tr>
</tbody>
I need to do so when you click on the row, new row is showing up, but when you click on another row I need the first one to hide.
Here is table in browser with an active row:
I have tried to do this with ng-show like this:
ng-show="activeRow==car.name"
activeRow is a $scope variable inside of my controller. The problem is, that new row is showing up, but not hiding when you click on another.
How can I fix that?
You need to provide a namespace for your activeRow variable because ng-repeat has its own scope.
<div ng-app="app" ng-controller="mainCtrl as main">
<table class="table table-striped table-bordered">
<tbody>
<tr ng-repeat-start="car in carList | filter:tableFilter" ng-click="main.activeRow = car.name">
<td><a target="_blank" href="{{car.carLink}}">{{car.name}}</a></td>
<td>{{car.review}}</td>
<td>{{car.rating}}</td>
<td>{{car.fiveStarPercent}}</td>
<td>{{car.recommended}}</td>
<td>{{car.price}}</td>
</tr>
<tr ng-repeat-end ng-show="main.activeRow==car.name">
<td colspan="6">{{car.name}}</td>
</tr>
</tbody>
</table>
</div>
Working demo using the "controller as" technique: http://codepen.io/Chevex/pen/KAmFB
This technique is functionally identical to doing this in your controller:
app.controller('mainCtrl', function ($scope) {
$scope.main = this;
this.activeRow = "Lightning McQueen";
});
Angular allows the "as" syntax in ng-controller definitions as a simple shortcut for creating a namespace on your scope that refers to the controller function's execution context (this). It's a nice way to create a namespace without having to create a random meaningless object such as $scope.model = { ... };.
Since the ng-repeat directive creates a new scope and the activeRow property is on the parent's controller scope, you will have to encapsulate that property inside an object. This way scope's prototypal inheritance will work as expected.
On the controller:
$scope.model = { activeRow: 'someValue' };
And on the HTML:
ng-show="model.activeRow == car.name"
More info on prototypal inheritance here.
I may be a bit confused about scope (I've read a lot of tutorials about it, but at this point I don't understand how to make this thing), anyway, this is what I'm trying to do:
I have a table with various cells
<table my-table>
<tr>
<td my-table-cell>
<span ng-if="!myTableCellStatus.editing">Bla 1</span>
<input ng-if="myTableCellStatus.editing" type="text" name="value" value="Bla 1">
</td>
<td my-table-cell>
<span ng-if="!myTableCellStatus.editing">Bla 2</span>
<input ng-if="myTableCellStatus.editing" type="text" name="value" value="Bla 2">
</td>
</tr>
<tr>
<td my-table-cell>
<span ng-if="!myTableCellStatus.editing">Bla 3</span>
<input ng-if="myTableCellStatus.editing" type="text" name="value" value="Bla 3">
</td>
<td my-table-cell>
<span ng-if="!myTableCellStatus.editing">Bla 4</span>
<input ng-if="myTableCellStatus.editing" type="text" name="value" value="Bla 4">
</td>
</tr>
</table>
And my-table-cell directive
angular.module('myApp').
directive('myTableCell', [
->
require: '^myTable'
restrict: 'AC'
scope: {}
link: ($scope, element, attrs, myTable) ->
# XXX: I have some code here that allows me to access the cell from myTable
# I change the status from there
myTable.addCell(
changeStatus: (status) ->
$scope.$apply ->
$scope.myTableCellStatus.editing = status
cell: element
)
$scope.myTableCellStatus =
editing: false
])
Now, my idea was: make my-table-cell a directive with isolated scope. Then access it in its child to show/hide various elements.
Is this possible? In my code, looks like I can't in any way bind to any value of my-table-cell scope, probably because it's isolated.
Considering I'm confused, a code example about it would be lovely, I initially thought this would be the right approach, but now looks like I'm completely wrong.
Isolate scope is good most of the time, but in your case it won't help. If you want to have HTML inside your directive and you want to expose custom properties to those HTML elements (e.g. myTableCellStatus) - and since this HTML is not coming from your directive's template - you need a "normal" (i.e. non-isolate) scope:
app.directive('myTableCell', function () {
return {
...
scope: true,
link: function postLink(scope, element, attrs, myTable) {
...
scope.myTableCellStatus = {editing: false};
}
};
});
See, also, this short demo.
When you define an isolated scope for your directive, you are defining a private sandbox for your scope variables. Variables defined or referenced from the isolated scope will not use scope inheritance to resolve bindings.
To fix this, you can either pass in your models into your isolated scope from your parent scope through the element attributes. In your directive definition:
scope: {
myTableCellStatus: '='
}
This sets up a two-way model binding between the myTableCellStatus variable resolved on parent scope and the scope variable on your isolated scope with the same name.
Or you can reference $parent inside your link function:
$scope.$parent.myTableCellStatus
This works because you are referencing the parent scope from your isolated scope, which does use scope inheritance to resolve bindings.
[EDIT]
It might be obvious now that if you reference $parent, you are reaching out from your isolated scope and into your parent scope, which if shared will bind to the same model across all your directives. This would work if you're inside a an ng-repeat, since it creates a child scope. But if you're not inside a child directive, the model would be shared.