Access a ng-repeat scope from a controller - javascript

I'm trying to display some comment with two nested ng-repeat:
<div ng-repeat="element in elements" >
<ul>
<!-- comments -->
<li ng-repeat="comment in comments">
<span>Comment</span> <strong>{{comment.username}}</strong>
<blockquote>{{comment.content}}</blockquote>
</li>
</ul>
</div>
Here's what's in the controller:
$scope.comments = [];
$scope.populateComments = function(content_id){
ProjectsService.commentsQuery(content_id)
.then(function (data) {
$scope.comments = data;
})
}
$scope.populateComments(element.id);
Obviously it's not working, my problem is that I don't know how, nor if it's possible, to access the property of an object of the ng-repeat scope (to get element.id and get only the comments related to the element involved).
Any ideas?
Thank you in advance!

You can access the property of an object of the ng-repeat scope. You need to re-factor your code.
In Html
<div ng-repeat="element in elements" >
<ul>
<!-- comments -->
<li ng-repeat="comment in element.comments">
<span>Comment</span> <strong>{{comment.username}}</strong>
<blockquote>{{comment.content}}</blockquote>
</li>
</ul>
</div>
In JS
$scope.populateComments = function(element){
ProjectsService.commentsQuery(element.id)
.then(function (data) {
element.comments = data;
})
}
$scope.populateComments(element);

Related

Angular http data displaying in one div but not the other

I am using ng-repeat to print a list of posts to the page via the WordPress REST-API. I am using Advanced Custom Fields on each post. From what I can see everything is working, but the post data is not showing in one container, yet it is displaying in another. I should also mention that this is set up like tabs. (user clicks a tab for a post and it displays that posts data)
var homeApp = angular.module('homeCharacters', ['ngSanitize']);
homeApp.controller('characters', function($scope, $http) {
$scope.myData = {
tab: 0
}; //set default tab
$http.get("http://bigbluecomics.dev/wp-json/posts?type=character").then(function(response) {
$scope.myData.data = response.data;
});
});
homeApp.filter('toTrusted', ['$sce',
function($sce) {
return function(text) {
return $sce.trustAsHtml(text);
};
}
]);
HTML:
<section class="characters" ng-app="homeCharacters" ng-controller="characters as myData">
<div class="char_copy">
<h3>Meet the Characters</h3>
<div ng-repeat="item in myData.data" ng-bind-html="item.content | toTrusted" ng-show="myData.tab === item.menu_order">
<!--this is the section that will not display-->
<h3>{{ item.acf.team }}</h3>
<h2>{{ item.acf.characters_name }} <span>[{{item.acf.real_name}}]</span></h2>
<p class="hero_type">{{ item.acf.hero_type }}</p>
{{ item.acf.description }}
Learn More
</div>
</div>
<div class="char_tabs">
<!--if I put the identical {{}} in this section it WILL display-->
<nav>
<ul ng-init="myData.tab = 0" ng-model='clicked'>
<li class="tab" ng-repeat="item in myData.data" ng-class="{'active' : item.menu_order == myData.tab}">
<a href ng-click="myData.tab = item.menu_order">
<img src="{{ item.featured_image.source }}" />
<h3>{{ item.title }}</h3>
</a>
</li>
</ul>
</nav>
</div>
</section>
I should also mention that I use Ng-inspector, and it does show the data being pulled in. I can confirm this via the console. I have checked to ensure no css is in play; the div is totally empty in the DOM.
I appreciate all the help the GREAT angular community has shown!
The problem is you had used ng-bind-html over ng-repeat element which is changing the inner content of ng-repeat div. I guess as you have inner transcluded template inside ng-repeat directive, you should not be using ng-bind-html there in a place.
Markup
<div ng-repeat="item in myData.data" ng-show="myData.tab === item.menu_order">
<!--this is the section that will not display-->
<h3>{{ item.acf.team }}</h3>
<h2>{{ item.acf.characters_name }} <span>[{{item.acf.real_name}}]</span></h2>
<p class="hero_type">{{ item.acf.hero_type }}</p>
{{ item.acf.description }}
Learn More
</div>

ng-include with template does not render data

I have two java script - one for controller and one for data service call.
On index page, I try to load tab with data from database returned results. It throws undefined for scope data which I can see already set but it seems html renders before that
Index page
<li ng-repeat="(Id, Name) in data.list" ng-class="{active: isSel(Id)}">
<a ng-click="isChange(Id, Name);" ng-href="#{{Name}}" role="pill" data-placement="right" data-toggle="tab">
{{Name}}
</a>
</li>
<div class="tab-content">
<div ng-repeat="(Id, Name) in data.list" class="tab-pane template fade in" id="{{Name}}" ng-class="{active: isSel(Id)}">
<div class="row" ng-include="'templates/my_widget.html'" > </div>
</div>
</div>
my_widget.html
<div class="col-md-4 component list-widget" ng-repeat="(Id, Name) in data.LatestBList">......blah blah....</div>
Controller
$scope.isSelected = function(entry) {
return $scope.tab === entry;
};
$scope.isChange = function(Id, Name) {
$scope.tab = Id;
$scope.Name = Name;
$scope.data.LatestBList= [];
$scope.data.LatestBList= ds.getList($scope.Name); // database retuned list
};
I get the error like
Error: [ngRepeat:dupes] http://errors.angularjs.org/1.4.3/ngRepeat/dupes?p0=(Id%2C%20Name)%20in%20data.LatestBList&p1=undefined%3Aundefined&p2=undefined
at Error (<anonymous>
Any suggestion ?
ng-include gets created with its own scope hence it was returning undefined. $parent can be used to obtain the parent scope which solved the issue.

AngularJS ng-if inside ng-repeat does not work

Here is my code:
<body ng-controller="QueryCntl">
<div>
<h1> Target:{{target}}</h1>
</div>
<div ng-app="myApp" ng-controller="mytableCtrl">
<div ng-include="'header.html'"></div>
<div id="menuList">
<ul class="menuNav">
<li class="menuList_Slide" ng-repeat="x in names">
<div>
{{ x.category }}
</div>
<div ng-if="{{target}} == {{x.id}}"> //Display subcategory if true
<ul id="subCategories">
<li>
Childid should be displayed
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
<script>
var app = angular.module('myApp', [], function($locationProvider) {
$locationProvider.html5Mode(true);
});
function QueryCntl($scope, $location) {
$scope.target = $location.search()["categoryid"];
}
app.controller('mytableCtrl', function($scope, $http) {
$http.get("api/topCategories")
.success(function(response) {$scope.names = response;});
});
</script>
I want to display only 1 subcategory if {{target}} is equal to {{x.id}}. But for now it prints everything... {{target}} gets value from the url where ?categoryid=some_number and x.id is a value from DB. These values works fine in my code.
I would appreciate any help.
EDIT: ng-if="target == x.id" does not help.
ngIf doesn't need to use {{}} - it's already an Angular expression:
div ng-if="target == x.id"
Problem solver:
I inserted
<base href="category.html">
in head tags and deleted bad script source.
You don't need to interpolate properties within the ng-if directive's conditional as Angular evaluates the complete expression against the scope already. Try this:
ng-if="target == x.id"
Replace:
<div ng-if="{{target}} == {{x.id}}">
With:
<div ng-if="target == x.id">
The ng-if attribute should contain plain JavaScript, instead of those interpolation tags ({{}}).
This holds true for all ng- attributes.
ngIf directive expects an expression, so you don't need interpolation tags:
<div ng-if="target == x.id"> //Display subcategory if true
<ul id="subCategories">
<li>
Childid should be displayed
</li>
</ul>
</div>
And one more thing: you are not initializing $scope.target because corresponding controller is outside of the ng-app. Remove ng-controller="QueryCntl" and add target initialization into mytabeCtrl:
app.controller('mytableCtrl', function($scope, $http) {
$scope.target = $location.search()["categoryid"];
$http.get("api/topCategories")
.success(function(response) {$scope.names = response;});
});

angular.js ng-repeat li items with html content

I have a model that comes back from the server which contains html instead of text (for instance a b tag or an i tag)
when I use ng-repeat to built a list out of it it shows the html as pure text, is there a built in filter or directive that put's the html inside the li items or not? I've looked in the documentation but since I'm still very new to it I'm having difficulties finding it.
ng-repeat:
<li ng-repeat="opt in opts">
JSFiddle:
http://jsfiddle.net/gFFBa/1/
It goes like ng-bind-html-unsafe="opt.text":
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat=" opt in opts" ng-bind-html-unsafe="opt.text" >
{{ opt.text }}
</li>
</ul>
<p>{{opt}}</p>
</div>
http://jsfiddle.net/gFFBa/3/
Or you can define a function in scope:
$scope.getContent = function(obj){
return obj.value + " " + obj.text;
}
And use it this way:
<li ng-repeat=" opt in opts" ng-bind-html-unsafe="getContent(opt)" >
{{ opt.value }}
</li>
http://jsfiddle.net/gFFBa/4/
Note that you can not do it with an option tag: Can I use HTML tags in the options for select elements?
Note that ng-bind-html-unsafe is no longer suppported in rc 1.2. Use ng-bind-html instead. See: With ng-bind-html-unsafe removed, how do I inject HTML?
You can use NGBindHTML or NGbindHtmlUnsafe this will not escape the html content of your model.
http://jsfiddle.net/n9rQr/
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat=" opt in opts" ng-bind-html-unsafe="opt.text">
{{ opt.text }}
</li>
</ul>
<p>{{opt}}</p>
</div>
This works, anyway you should be very careful when using unsanitized html content, you should really trust the source of the content.
use ng-bind-html-unsafe
it will apply html with text inside like below:
<li ng-repeat=" opt in opts" ng-bind-html-unsafe="opt.text" >
{{ opt.text }}
</li>
Here is directive from the official examples angular docs v1.5 that shows how to compile html:
.directive('compileHtml', function ($compile) {
return function (scope, element, attrs) {
scope.$watch(
function(scope) {
return scope.$eval(attrs.compileHtml);
},
function(value) {
element.html(value);
$compile(element.contents())(scope);
}
);
};
});
Usage:
<div compile-html="item.htmlString"></div>
It will insert item.htmlString property as html any place, like
<li ng-repeat="item in itemList">
<div compile-html="item.htmlString"></div>
If you want some element to contain a value that is HTML, take a look at ngBindHtmlUnsafe.
If you want to style options in a native select, no it is not possible.
ng-bind-html-unsafe is deprecated from 1.2. The correct answer should be currently:
HTML-side: (the same as the accepted answer stated):
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat=" opt in opts" ng-bind-html-unsafe="opt.text">
{{ opt.text }}
</li>
</ul>
<p>{{opt}}</p>
</div>
But in the controller-side:
myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
// ...
$scope.opts.map(function(opt) {
opt = $sce.trustAsHtml(opt);
});
}

Ng-repeat not rendering content

I'm writing a web app using Node.js+Express to serve (with HoganJs as a templating engine) and AngularJS on the frontend. I'm having problems with ng-repeat rendering the correct number of elements, but without any content in. I broke the ng-repeat down into a smaller example and it's still not rendering.
EDIT: There was a typo in the Plunkr, so I removed it. Here's a more expanded extract from my app.
Here's a section of my view: index.hjs
<div class="search-results" ng-controller="results">
<ul class="tracks">
<li class="track" ng-repeat="track in tracks">
<ul class="meta">
<li>
<div class="name">
<span class="value">{{track.name}}</span>
</div>
</li>
<li>
<div class="album">Album:
<span class="value">{{track.album}}</span>
</div>
</li>
<li>
<div class="artist">Artist:
<span class="value">{{track.artist}}</span>
</div>
</li>
<li>
<div class="length">Length:
<span class="value">{{track.length}}</span>
</div>
</li>
</ul>
</li>
</ul>
</div>
The results controller: js/controllers/results.js
var results = function($scope, socket) {
$scope.tracks = [
{"uri":"spotify:track:1jdNcAD8Ir58RlsdGjJJdx","name":"Ho Hey","artist":"The Lumineers","album":"The Lumineers"},
{"uri":"spotify:track:3uuGbRzMsDI5RiKWKOjqWL","name":"Hey Porsche","artist":"Nelly","album":"Hey Porsche"},
{"uri":"spotify:track:5BSndweF91KDqyxANsZcQH","name":"Ho Hey","artist":"The Lumineers","album":"The Lumineers"},
{"uri":"spotify:track:2UNc0duOP4cS7gqYFFkwxT","name":"Hey Girl","artist":"Billy Currington","album":"Hey Girl"},
{"uri":"spotify:track:6fgbQt13JlpN59PytgTMsA","name":"Snow [Hey Oh]","artist":"Red Hot Chili Peppers","album":"Snow [Hey Oh]"}
];
socket.on("results", function(tracks) {
$scope.tracks = tracks;
console.dir(JSON.stringify($scope.tracks));
});
$scope.add = function(uri) {
socket.emit("add", uri);
};
};
And finally my module: app.js
var app = angular.module("app", []);
var factories = {
socket: socket
};
app.factory(factories);
var controllers = {
actions: actions,
search: search,
results: results,
queue: queue
};
app.controller(controllers);
For testing purposes, the tracks are hardcoded in when the app is run 5 lis are rendered but there no content has been templated inside of them.
Remove a ) here:
];
});
^
Plnkr: http://plnkr.co/edit/e0URFt?p=preview
I've just realised what's happening here. Hogan.js is overwriting angular's templates when the page is rendered at the server.
Just remove the extra bracket added to your script (line 19). Please look at the script here.
http://plnkr.co/edit/sy2m0RuXRudGvjnmfC3Y?p=preview

Categories