access to scope of each ng-repeat item - javascript

I am sort of new to angularjs. I am using ng-repeat to list entities in my page, each entity object has an href property to it's fields. I want when someone clicks on the link, retrieve the fields and show them on another nested ul below the parent entity.
here's my html:
<ul>
<li class="" ng-repeat="entity in entities" >
{{entity.name}}
<a class="entity-fields" ng-click="retrieveFields(entity.fields.href)" >fields</a>
<ul class="fields" >
<li class="fields" ng-repeat="field in fields" > {{field.name}} </li>
</ul>
</li>
</ul>
and this is my javascript:
myApp.controller('excelController', ['$scope', '$http', function($scope, $http) {
$scope.baseUri = "http://localhost:8080/rst/api/v1/introspection";
$scope.entitiesUri = $scope.baseUri + "/entities";
$scope.retrieveFields = function(href){
$http.get(href).then(function success(response){
$scope.fields = response.data;
});
};
$http.get($scope.entitiesUri).then(function success(response){
$scope.entities = response.data;
});
}]);
but when I click on the link and retrieve fields of an entity, it shows them below all of the entities.
how can I make it to only show the fields in the scope of each item.
Thanks in advance

You have to change some part of your code
<ul>
<li class="" ng-repeat="entity in entities track by $index" >
{{entity.name}}
<a class="entity-fields" ng-click="retrieveFields($index,entity.fields.href)" >fields</a>
<ul class="fields" >
<li class="fields" ng-repeat="field in entity.fieldItems" > {{field.name}} </li>
</ul>
</li>
then You need to change your retrieve function as:
$scope.retrieveFields = function(index,href){
$http.get(href).then(function success(response){
$scope.entities[index].fieldItems = response.data;
});
};
This should fix your problem.

Related

Is this bug for using AngularJS to fetch data to <li><a href> or not?

I use the AngularJs to fetch the data from mySql database for my navigation bar on HTML5. The problem is I cannot open the link in the sub menu.
Here is my code :
<div id="header-wrapper" class="wrapper">
<div ng-app="myApp" ng-controller="customersCtrl" id="header">
<div id="logo">
<h1>Why Choose a Breeder ?</h1>
<p>Quality Quarantee Knowledge</p>
</div>
<nav id="nav">
<ul>
<li class="current">Home</li>
<li>Holland Lops
<ul>
<li>Bucks</li>
<li>Does</li>
<li>Junior</li>
</ul>
</li>
<li>For Sale</li>
<li>Article
<ul><li ng-repeat="menu in menues">{{menu.Title}}</li></ul>
</li>
<li>Contact us</li>
</ul>
</nav>
</div>
However I cannot open the link in this code (When I click on link, nothing happens):
<ul><li ng-repeat="menu in menues">{{menu.Title}}</li></ul>
But If I remove the ul like this :
<li>For Sale</li>
<li>Article</li>
<li ng-repeat="menu in menues">{{menu.Title}}</li>
I can open the link. I don't know what's wrong. Is it because the order of the navigation bar ? Could you please suggest me, what I'm wrong ?
This is my .js code :
var app = angular.module('myApp', []);
app.controller('customersCtrl', ['$scope','$http',function($scope, $http){
$scope.menues = [];
$http.get("http://www.rhosgobelrabbit.com/getUrl.php")
.then(function (data) {$scope.menues = data.data.records;
}, function (error) {
alert('Error');
});
}]);
You need to use ng-href instead of href. You can read about this in the angularJS docs: Docs
<ul><li ng-repeat="menu in menues"><a ng-href="{{menu.Link}}" target="_self">{{menu.Title}}</a></li></ul>
As long as the ng- aren't placed infront of the href will angular just give you a 404.

AngularJS: ng-repeat not working

The ng repeat is not working for my angular code.
Here is the partial:
<section class="artistpage">
<ul class="artistlist">
<li ng-model = "questions" ng-repeat="item in questions">
<input type="checkbox" name = "q">{{item.ct}}
</input>
</li>
</ul>
</section>
Here is the Controller:
var testControllers = angular.module('testControllers', []);
testControllers.controller('ListController', ['$scope', '$http', function($scope, $http) {
$http.get('js/cat.json').success(function(data) {
$scope.questions = data;
});
}]);
The data:
[
{
"info":{
"cid":1,
"ct":"T1",
"ctg":"math",
"pcid":78
}
},
{
"info":{
"cid":2,
"ct":"T2",
"ctg":"math",
"pcid":78
}
},
{
"info":{
"cid":3,
"ct":"T3",
"ctg":"Py",
"pcid":2
}
}
]
I have not been able to figure out why this is not working. Help please!
The problem here is you are not accessing the object info, you should access each element info and get the value
change your ng-repeat like this,
<li ng-model = "question" ng-repeat="item in questions">
{{item.info.ct}}
</li>
Working Plunker
You just need to replace {{item.ct}} with {{item.info.ct}} as you have object info inside your outer object. Check FIDDLE
<section class="artistpage">
<ul class="artistlist">
<li ng-model = "questions" ng-repeat="item in questions">
<input type="checkbox" name = "q"/>{{item.info.ct}}
</li>
</ul>
</section>
<section class="artistpage">
<ul class="artistlist">
<li ng-model = "question" ng-repeat="item in questions">
<input type="checkbox" name = "q">{{item.ct}}
</input>
</li>
</ul>
</section>
--------------use this-----------
<section class="artistpage">
<ul class="artistlist">
<li ng-model = "question" ng-repeat="item in questions">
<input type="checkbox" name = "q">{{item.info.ct}}
</input>
</li>
</ul>
</section>
ng-model should not be the same. so use ng-model="question" instead of questions
Here is plunker

Nested transclude directive renders inner transcluded content in wrong place

I have a myList directive, which transcludes it's content. The problem occurs when I try and nest a <my-list> element inside another <my-list>.
JS Fiddle: http://jsfiddle.net/fqj5svhn/
The directive:
var MyListDirective = (function () {
function MyListDirective() {
this.restrict = 'E';
this.replace = true;
this.transclude = true;
this.scope = {
myListType: '='
};
this.controller = function () {
this.classes = 'my-class';
};
this.controllerAs = 'myList';
this.bindToController = true;
this.template = '<ul ng-class="myList.classes" ng-transclude></ul>';
}
return MyListDirective;
})();
angular.module('myApp', []).directive('myList', function () {
return new MyListDirective();
});
Example usage of the directive:
<div ng-app="myApp">
<my-list my-list-type="'someType'">
<li>foo</li>
<li>bar</li>
<li>
<my-list my-list-type="'anotherType'">
<li>cats</li>
<li>dogs</li>
</my-list>
</li>
</my-list>
</div>
What gets rendered:
<div ng-app="myApp" class="ng-scope">
<ul ng-class="myList.classes" ng-transclude="" my-list-type="'someType'" class="ng-isolate-scope my-class">
<li class="ng-scope">foo</li>
<li class="ng-scope">bar</li>
<li class="ng-scope">
<ul ng-class="myList.classes" ng-transclude="" my-list-type="'anotherType'" class="ng-isolate-scope my-class">
</ul>
</li>
<li class="ng-scope">cats</li>
<li class="ng-scope">dogs</li>
</ul>
</div>
As you can see the list items from the inner myList appear to be transcluded by the outer myList.
What I want to happen:
<div ng-app="myApp" class="ng-scope">
<ul ng-class="myList.classes" ng-transclude="" my-list-type="'someType'" class="ng-isolate-scope my-class">
<li class="ng-scope">foo</li>
<li class="ng-scope">bar</li>
<li class="ng-scope">
<ul ng-class="myList.classes" ng-transclude="" my-list-type="'anotherType'" class="ng-isolate-scope my-class">
<li class="ng-scope">cats</li>
<li class="ng-scope">dogs</li>
</ul>
</li>
</ul>
</div>
Suggestions?
It is happening because when browser renders the page it expects <li> to be inside <ul>, but it your case it is inside <my-list> which is an invalid markup. All these things happen before Angular bootstraps and runs directives. There is no way you can predict how the browser would interpret your markup when it's invalid, in this particular case it pushes <li>'s out to be together.
In this fiddle I've replaced <ul> and <li> with <div>, which does not have any requirements for nesting, and transclusion works just fine.

When building a tree using ng-include, my 'ng-click' is not working

I'm building a tree using the following code with 'ng-include', and it's looking fine:
<script type="text/ng-template" id="tree_node.html">
<a ng-click="select(this, data, $event)">{{data.name}}</a>
<ul>
<li ng-repeat="data in data.children track by $index" ng-include="'tree_node.html'"></li>
</ul>
</script>
<div>
<ul>
<li ng-repeat="data in venueTree track by $index" ng-include="'tree_node.html'"></li>
</ul>
</div>
The problem is that when clicking on the {{data.name}}, the 'select' function isn't called in my controller. I have no javascript errors, just nothing happens.
reapter creating new scopes to you can access parent scope using $parent or ng-init like ie:
please see here: http://jsbin.com/xowub/3/edit
html:
<li ng-repeat="data in venueTree track by $index" ng-include="'tree_node.html'" ng-init="parent=this"></li>
script:
<script type="text/ng-template" id="tree_node.html">
<a ng-click="parent.select(this, data, $event)">{{data.name}}</a>
<ul>
<li ng-repeat="data in data.children track by $index" ng-include="'tree_node.html'"></li>
</ul>
</script>
I'm not sure I understand your problem. The ng-click seems to work just fine in this Plunk I made.
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.venueTree = [{children:[{name:'one'},{name:'dos'}]},{children:[{name:'drei'},{name:'fyra'}]}];
$scope.select = function(a,b,c){alert(b.name); console.log({a:a, b:b, c:c})};
});

AngularJS - parse JSON

I have a list of photographs being generated like the following snippet. Basically this would render a table like structure, with each photo being like a cell in this table. The ID of each photo like for example 1D means that the photo is in the first row of the table and in the 4th/D column.
<ul>
<li class="row">
<ul>
<li class="photo" id="photo-1A">1A</li>
<li class="photo" id="photo-1B">1B</li>
<li class="photo" id="photo-1C">1C</li>
<li class="photo" id="photo-1D">1D</li>
<li class="photo" id="photo-2A">2A</li>
<li class="photo" id="photo-2B">2B</li>
<li class="photo" id="photo-2C">2C</li>
<li class="photo" id="photo-2D">2D</li>
<li class="photo" id="photo-3A">3A</li>
<li class="photo" id="photo-3B">3B</li>
<li class="photo" id="photo-3C">3C</li>
<li class="photo" id="photo-3D">3D</li>
</ul>
</li>
</ul>
I have a JSON which includes whether the photo is available or not. Basically the JSON string is something along these lines:
[{"row":1,"position":"A","available":true},{"row":1,"position":"B","available":false},{"row":1,"position":"C","available":false},{"row":1,"position":"D","available":false},{"row":2,"position":"A","available":true},{"row":2,"position":"B","available":false},{"row":2,"position":"C","available":false},{"row":2,"position":"D","available":false},{"row":3,"position":"A","available":true},{"row":3,"position":"B","available":false},{"row":3,"position":"C","available":false},{"row":3,"position":"D","available":false}]
Now basically what I need to do is to parse this JSON string and when any of these photos have "available:true" in the JSON string, I add a class photo-available in the HTML. I am new to angular and I am not sure if there is an easy way to assign a class to the available photos. Would be glad if someone can tell me what to use or how to do it.
Edit: Angular Code is this:
<ul class="table-rows">
<li class="photo-row" ng:repeat="photo in photos" ng:class="'photo-' + photo.row + photo.position">
<ul class="table-photos">
<li class="photo photo-available" ng:class="selectedOrNot(photo)" ng:init="photo.selected = false" ng:click="photo.selected = !photo.selected">
<div class="photo-number">{{photo.row + photo.position}}</div>
</li>
</ul>
</li>
<div class="clear"></div>
Update3
The reason you are unable to restore previous selections is that you are overwriting the photo's selected property with ng-init:
ng:init="photo.selected = false"
ng-class="{'selected': photo.selected, 'available': photo.available}"
When you combine these two, the 'selected' class will never be added because photo.selected has been hardcoded to false. You just need to remove ng-init, and the previous selection will trigger ng-class to add the correct class.
Here is a working demo: http://plnkr.co/tVdhRilaFfcn55h6mogu
Original answer
If the list of photos is not the same array as the list of available photos, you can use a directive to add the class.
app.directive('availablePhoto', function($filter) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attr) {
var id = attr.id
var regex = /photo-(.)(.)/g;
var match = regex.exec(id);
var row = match[1]
var position = match[2]
var photo = $filter('filter')(scope.photos, {row:row, position:position}, false)
console.log(photo);
if (photo[0].available) {
element.addClass('available');
}
}
}
});
Then attach it to each list item like this:
<li class="photo" id="photo-1A" available-photo>1A</li>
Here is a demo: http://plnkr.co/WJCmLf2M39fcUnvOPyNA
Update1
Based on your update, I see that there is just one array populating the list, and it contains the available flag. Therefore, you don't need a custom directive - ngClass will work. Here it is integrated into your code sample:
<ul class="table-rows">
<li class="photo-row" ng:repeat="photo in photos" ng:class="'photo-' + photo.row + photo.position">
<ul class="table-photos">
<li class="photo" ng-class="{'available': photo.available}" ng:init="photo.selected = false" ng:click="photo.selected = !photo.selected">
<div class="photo-number">{{photo.row + photo.position}}
</div>
</li>
</ul>
</li>
<div class="clear"></div>
</ul>
I have update the plunker to demonstrate this.
http://plnkr.co/WJCmLf2M39fcUnvOPyNA
Update2
Since you need ngClass to add multiple classes, use it like this:
ng-class="{'selected': photo.selected, 'available': photo.available}"
Demonstration of selected + available: http://plnkr.co/WJCmLf2M39fcUnvOPyNA
Here's a plnkr with an example of how to solve your problem. You need to
make use of both the ng-repeat and the ng-class:
http://plnkr.co/edit/hk68qp4yhEjcvOkzmIuL?p=preview
As you can see, I also added some filters for your photos, they will come handy if you need to just show the available ones (for some reason).
Here's the documentation for angular $filter service
I think this meets all your requirements:
$scope.photos = JSON.parse('[{"row":1,"position":"A","available":true},{"row":1,"position":"B","available":false},{"row":1,"position":"C","available":false},{"row":1,"position":"D","available":false},{"row":2,"position":"A","available":true},{"row":2,"position":"B","available":false},{"row":2,"position":"C","available":false},{"row":2,"position":"D","available":false},{"row":3,"position":"A","available":true},{"row":3,"position":"B","available":false},{"row":3,"position":"C","available":false},{"row":3,"position":"D","available":false}]');
and then you can just use ng-repeat to build the list:
<ul>
<li class="row">
<ul>
<li ng-repeat="photo in photos" class="photo" ng-class="{'photo-available': photo.available}" id="photo-{{photo.row}}{{photo.position}}">{{photo.row}}{{photo.position}}</li>
</ul>
</li>
</ul>
So what we are doing is we are taking our photo array, and for every one (ng-repeat="photo in photos") we are assigning that specific item to the variable photo. Then, if photo.available is true, we assign the class photo-available (ng-class="{'photo-available': photo.available}").
Then, we can simply interpolate the id and text based off the properties row and position ({{photo.row}}{{photo.position}}). You could also have done that like this {{photo.row + photo.position}} but that could cause issues if they were both numbers.
http://plnkr.co/edit/hBkoyHVtIwF60MKDF84j?p=preview

Categories

Resources