Angular -- accessing variables defined inside ngRepeat from outside - angularjs

I am implementing in-place element editing in my Angular app and based my code on this answer https://stackoverflow.com/a/15453512/2026098, using an editing variable for each entry inside ng-repeat.
See http://jsfiddle.net/LYtQU/2/.
I would now like to access this variable from outside the scope of ng-repeat in order to conditionally show/hide an element. Basically, I would like to do something like ng-hide="if any entry has editing==true":
<div class="note" ng-hide="if any entry has editing==true">This should disappear when any entry is being edited</div>
<div class="entry"
ng-repeat="entry in entries"
ng-class="{'editing': editing}">
<span ng-hide="editing" ng-click="editing=true">{{ entry.name }}</span>
<span ng-show="editing" ng-click="editing=false">Editing entry...</span>
</div>
I am trying to avoid using jQuery as the editing variable seems perfect for the job, but just out of reach from my comprehension...

Set up a count in the controller and increment/decrement everytime editing is toggled. Then show the message if the count is 0.
function MainCtrl($scope) {
$scope.state = {editing: 0};
$scope.entries = [{name: 'Entry 1'}, {name: 'Entry 2'}];
};
<body ng-app>
<div ng-controller="MainCtrl">
<div class="note" ng-show="state.editing == 0">This should disappear when any entry is being edited</div>
<div class="entry"
ng-repeat="entry in entries"
ng-class="{'editing': editing}">
<span ng-hide="editing" ng-click="editing=true; state.editing = state.editing + 1">{{ entry.name }}</span>
<span ng-show="editing" ng-click="editing=false; state.editing = state.editing - 1">Editing entry...</span>
</div>
</div>
</body>
http://jsfiddle.net/LYtQU/5/

Related

In what scope is ng-repeat "as alias" available

I'm using angular 1.4.8. I want to save filtered result from ng-repeat and use it to determine whether to enable a "load more" button at the bottom of the list. I have looked at this question:
AngularJS - how to get an ngRepeat filtered result reference
And many others, they suggest to use "as alias" from ng-repeat, here's what my code looks like:
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in items | limitTo: totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
{{filteredResult.length}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="totalDisplayed <= filteredResult.length">
more
</button>
However, I found filteredResult.length is displayed fine right after ng-repeat, but the button is never shown. If I try to display filteredResult.length in where the button is, it will show null.
So is there a rule for "as alias" scope? I've seen plenty of examples work but mine doesn't, what am I missing here?
EDIT:
The accepted answer uses controllerAs which indeed will resolve the problem. However, charlietfl's comment using ng-init to save filteredResult to parent scope is also very neat and that's the solution I use in my code eventually.
Probably some of classes in your <ul class="media-list tab-pane fade in active"> or <li class="media"> is selector for a directive that would have its own scope. So you store filteredResult in e.g. tab-pane's scope and then try to have access out of it's scope in outside of ul tag.
Try to use Controller as instead of scope:
angular
.module('plunker', [])
.controller('MainCtrl', function() {
vm = this;
// make an array from 1 to 10
var arr = [];
while (arr.length < 10) {
arr.push(arr.length + 1)
};
vm.items = arr;
vm.totalDisplayed = 5;
vm.filteredResult = [];
});
<body ng-controller="MainCtrl as main">
{{main.items}}
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in main.items | limitTo: main.totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
filteredResult = {{main.filteredResult = filteredResult}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="main.totalDisplayed <= main.filteredResult.length">
more
</button>
</body>
http://plnkr.co/edit/drA1gQ1qj0U9VCN4IIPP?p=preview

How to create div and assign object to dataset dynamically using Angularjs

I have below div (class name 'sp') which I would like to dynamically create based on the sk from a dataset object.
div code
<div style="" class="swindow">
<div class="sp" style="">
<div class="svis" style="">
<div style="height:95%;width:95%;margin-top:0px;margin-left:5px;">
<chart dsn="dyndata" editable="false" labelled="true"></chart>
</div>
</div>
<div class="sdata" style="">
<div class="stext" style="">Average:78% </div>
</div>
</div>
While searching for similar examples, I came across ng-repeat in Angular js and I thought it might suit for this kind of objective.
But am very new to Angular js and not sure how to assign the data to my dyndata variable dynamically and create new div (class=sp) for each of the given id.
Here is the lookup object
[
{"id":20,"st":[{"label":"Audi","value":10},{"label":"BMW","value":70}]},
{"id":26,"st":[{"label":"Benz","value":40},{"label":"BMW","value":20}]},
{"id":12,"st":[{"label":"AUDI","value":60},{"label":"Tesla","value":70}]},
{"id":57,"st":[{"label":"MZ","value":30},{"label":"Honda","value":40}]}
]
When I input the id's as a set [12,26,57] - Three divs (each for #sp) should get created one for each of ids. In those, each div should have the dyndata assigned with the respective 'st' from above javascript object.
I could create div's in jquery using .append function to the container (#swindow) each time when I need. But am not sure how to assign sk as input to dyndata dataset for each div that gets created.
Could you please share how this can be achieved using Angular js ?
Here is the angular js code I used -
<script>
var app = angular.module('ExampleApp', ['ui.plot']);
app.controller('PlotCtrl', function ($scope) {
$scope.dyndata={};
});
</script>
I'm not exactly sure what you're trying to do but I think it should look something like this. Here is a plnkr..
Controller:
app.controller('PlotCtrl', function($scope) {
$scope.items = [
{"id":20,"st":[{"label":"Audi","value":10},{"label":"BMW","value":70}]},
{"id":26,"st":[{"label":"Benz","value":40},{"label":"BMW","value":20}]},
{"id":12,"st":[{"label":"AUDI","value":60},{"label":"Tesla","value":70}]},
{"id":57,"st":[{"label":"MZ","value":30},{"label":"Honda","value":40}]}
]
});
HTML:
<body ng-controller="PlotCtrl">
<div style="" class="swindow">
<div class="sp" style="" ng-repeat="item in items">
<div class="svis" style="">
<strong>{{item.id}}:</strong>
<div>-{{item.st[0].label}}</div>
<div>-{{item.st[1].label}}</div>
<div style="height:95%;width:95%;margin-top:0px;margin-left:5px;">
<chart dsn="dyndata" editable="false" labelled="true"></chart>
</div>
</div>
<div class="sdata" style="">
<div class="stext" style="">Average:78% </div>
<br>
</div>
</div>
</div>
</body>

Add in Hash and update DOM element dynamically using ng-repeat

I have hash of users as the following:
{"A1": {name: "Demo-1", status: "active"}, "A2": {name: "Demo-2", status: "deactive"}};
And I have two hashes of active/deactive users, and I make the table of each of them as the following:
<tr ng-repeat="(id, user) in deactiveUsers">
<td>
{{ user.name }}
</td>
<td>
<button type="button" ng-click="change(id)">Active</button>
</td>
</tr>
And If I click on Active button, I remove the object from deactiveUsers, and add it in activeUsers, the change function as the following:
$scope.change = function(id){
if($scope.users[id].status == "active"){
delete $scope.activeUsers[id];
$scope.users[id].status = "deactive";
$scope.deactiveUsers[id] = $scope.users[id];
}else{
delete $scope.deactiveUsers[id];
$scope.users[id].status = "active";
$scope.activeUsers[id] = $scope.users[id];
}
}
This my demo, it's working well if I tried it on plnkr. But on my localhost the deleting only is working, when I add on activeUsers the DOM element doesn't update with the new record.
I can't find out the issue.
How can I add in Hash to update the DOM element dynamically ?
why it's working on plnkr, but the same code doesn't work on localhost ?
You have multiple body tags in your DOM. I think the first (after the first table element) cause the others angular directives are outside the app.
Replace the body in your table elements by tbody elements.
Edit By the question's owner
My Error was I developed the tables as the following:
<div class="panel panel-primary" ng-controller="ExampleCtrl">
<table></table>
</div>
<div class="panel panel-primary" ng-controller="ExampleCtrl">
<table></table>
</div>
So, I called ng-controller twice, I fixed it by develop one div for the both as the following:
<div ng-controller="ExampleCtrl">
<div class="panel panel-primary">
<table></table>
</div>
<div class="panel panel-primary">
<table></table>
</div>
</div>

ng-repeater issue Duplicates in a repeater is not allowed

I'm trying to create a form like below, this using ng-repeat directive in angular and it whenever I created a new row complains
"Duplicates in a repeater are not allowed.".
While I understand the solution for this is by putting "track by $index", however it causes another issue, which clicking delete on one row deletes the value of other field. So I suspect that track by index is OK for static text but not input form. So how to use ng-repeat correctly for my case? See my JSFiddle for demo.
My current code :
HTML
<div class="row-fluid spacer10">
<a ng-click="addAKA()" class="btn btn-primary spacer5 left30"><i class="icon-plus icon-white"></i> Add New Alias</a>
</div>
<div class="row-fluid spacer10"></div>
<div class="row-fluid spacer5" ng-repeat="item in aliasList track by $index">
<input type="text" class="span6 left30" ng-model="item">
<button class="btn btn-danger" ng-click="deleteAKA($index)">delete</button>
<BR/>
</div>
Javascript
$scope.addAKA = function ()
{
if($scope.aliasList == null)
{
$scope.aliasList = [];
}
$scope.aliasList.push("");
$scope.aliasjson = JSON.stringify($scope.aliasList);
}
$scope.deleteAKA = function (idx)
{
var aka_to_delete = $scope.aliasList[idx];
$scope.aliasList.splice(idx, 1);
$scope.aliasjson = JSON.stringify($scope.aliasList);
}
Just change the way you iterate. Instead of this:
<div ng-repeat="item in aliasList track by $index">
do this:
<div ng-repeat="item in aliasList">
$index will be still available inside the element, use like this:
<button ng-click='deleteItem($index)'>Delete</button>
See this JSFiddle for a correct solution
There are multiple problems with your approach.
Since you are directly binding a string to ng-model and ng-repeat creates a child scope, any change to the value would not reflect back. Change you scope model to something like
$scope.list = [{text:"one"},{text:"two"}];
and bind to i.text instead of binding to i as you did earlier.
The deleteItem method was called using item instead of index. See my fiddle here
http://jsfiddle.net/JS6aJ/1/

[Angular JS]- Tabs Pane Example - Dynamic Add Tab

I have used the example from Angular JS Homepage and modified it to meet the requirements.
I have added the tabs info in a scope array and manipulate the data based in some conditions.
Issues:
I have attached an ng-bind on tabItem.title, so any change in the text box will update the title, but i want to limit the displaying of the title by 10 chars
When i create a new tab, i want that tab to be the selected one.
How can i select a tab based on some action taken (like on a click move from tab 1 to tab 2)
Fiddle: http://jsfiddle.net/austinnoronha/NWwcT
<br/><br/>
<div ng-cloak ng-app="TabsApp">
<div class="container" ng-controller="TabManagerCtrl">
<span class="label label-info label-ext" ng-click="tabManager.addTab()" style="cursor:pointer">Add a Tab</span><br/><br/>
<div>
<div tabs>
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title }}">
<p>{{ tabInfo.content }}</p>
<input type="text" ng-model="tabInfo.title" ng-change="tabManager.getTitle(tabInfo)">
</div>
</div>
</div>
<br/><br/><br/>
</div><!-- /container -->
</div> <!-- /container -->
</div> <!-- /app -->
that's strange...
The limitTo filter doesn't seem to work, but you can create a new one and change your line
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title }}">
by
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title | limit:10}}">
with
angularApp.filter('limit', function() {
return function (input, value) {
return input.substr(0,value);
};
});
For the select one, I think it doesn't work because you have to have access to the pane scope. One way to do it is to access to access the property from the pane when you create it. In the pane directive, just add :
if(scope.$parent.tabInfo.selected) tabsCtrl.select(scope);
just after the tabsCtrl.addPane(scope); line. But then you also have to change the tabs directive so that the line
$scope.select = function(pane) {
become
this.select = $scope.select = function(pane) {
For your 3rd question, I don't know how to do it in that scheme.
I would make the pane directive different, putting the select function out of the directive, and binding it directly to your tabManager object.
Like this : http://jsfiddle.net/NWwcT/2/
In this cas, you have the 3 requirements, and you can select the tab from ouside by calling tabManager.select(index)

Resources