I have created a inline directive to display comments from a Java-Script Array. The structure of comments array is as follows
$scope.comments = [{
userName: 'TestUser',
comment : 'Parent Comment',
comments: [ ] //Holds the Replies
}];
I am programmatically adding the replies to comments array in the $scope.comments array.
The Inline Directive snippet is as follows
<div>
<script type="text/ng-template" id="categoryTree">
<div class="media-body">
<h4>{{ comment.userName }} </h4>
<p> {{ comment.comment }} </p>
</div>
<ul ng-if="comment.comments">
<li ng-repeat="comment in comment.comments" ng-include="'categoryTree'">
</li>
</ul>
</script>
<ul>
<li ng-repeat="comment in comments" ng-include="'categoryTree'"></li>
</ul>
</div>
When I add the parent comments to $scope.comments, they are getting shown. However, when I add reply to comments array in the $scope.comments array, it is not getting shown.
Also, if I initialize the $scope.comments with all comments and replies in angular.element(document).ready, they are shown correctly
Please let me know where I am going wrong and how to fix it.
Other Info
All of this works correctly when I use directive in independent page, but started to get problems when I am using this content in "ng-view"
This behavior was considered as a bug, which has been fixed in the later versions of AngularJS. The above example works fine with AngularJS version 1.4.0
Related
I have an array of comments. For each of the comment, I have a hidden form where you can reply. That item in each object of the array is called: comment.showSubCommentForm. When I click on Reply, I want to be able to reply with a comment and the function called: commentOnSubPost.
I load my data in chunks of 10 (lazy loading) which I am doing by using the infinite-scroll-distance Angular module. Every time I reach the end of the page, I get the next 10 items and add them to the $scope.comments array, which you can see below is what I am running my ng-repeat on .
The problem is that, although the commentOnSubPost works really well as in it adds the reply to the comment, I have reload the data so I can get the updated $scope.comments with the new reply. BUT - as I have implemented lazy loading, how do I do that if say I am on the 20th page?
I looked at some similar posts but their approach from mine was very different so am very lost.
My HTML:
<div infinite-scroll='loadMore()' infinite-scroll-distance='1'>
<div class="row">
<div ng-repeat="comment in comments track by $index">
<ul class="comments">
<li class="clearfix">
<a ng-href="#">SomeLink</a>
<div>
<p >{{ comment.date }} <a ng-href="/wall#/profile/main/{{ comment.userID }}">{{ comment.fullname }}</a> says <i class="commentReply"><a href ng-click="comment.showSubCommentForm = !comment.showSubCommentForm"><small>Reply</small></a></i></p>
<p class="mainComment">
{{ comment.comment }}
<p class="meta"><i class="showReply"><a href ng-click="comment.showReplies = !comment.showReplies"><small>Show Replies</small></a></i></p>
</p>
</div>
<div ng-show="comment.showSubCommentForm">
<form ng-submit="commentOnSubPost( post._id, comment._id, subComment)">
<div class="form-group">
<div class="form-group">
<textarea ng-model="subComment" class="form-control" placeholder="Reply to the above comment"></textarea>
</div>
<input type="submit" value="Reply">
</div>
</form>
<div ng-show="comment.showReplies" ng-repeat="subComment in comment.subComments track by $index">
<ul class="comments">
<li class="clearfix">
<a ng-href="/wall#/profile/main/{{ comment.userID }}"><img ng-src="{{ subComment.profilePic }}" class="avatar" style="border-radius: 50%"></a>
<div class="post-subComments">
<p class="meta">{{ subComment.date }}<a ng-href="SomeLink"> {{ subComment.fullname }}</a></p>
<p>
{{ subComment.comment }}
</p>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
I won't add too much information here as I don't want to overload this post but if you need any particular information, please do let me know. I just need to know how do I reload the data (or not if there's another approach) so that I can get the latest data.
I hope this makes sense.
Thanks in advance!
Like you have $scope.comments = []; then on each call you just have to append upcoming data to this array.
Like $scope.comments = $scope.comments.concat(response.data);
In this way lazy loading will work.
I fixed this with making a Node route which gives back the exact comment I have just added. Then, I found that commentID in my $scope.comments and made it's subCommenemts to the one I have locally.
It does the job and the data is real. One drawback is that if at that time, there's another comment, it won't show up until the page's refreshed but I'm not too fussed about that.
I have a list that displays documents tied to a case number. I am displaying them as follows:
<ul class="doc-list">
<li ng-repeat="docs in casedocs">
<a ng-href="#" ng-click=loadDocument(docs.Doc_Path)>{{docs.Description}}</a>
</li>
</ul>
This works just fine. However, if I add anything in front of the list item I get many empty rows added to the list. For instance, if I change the code to be:
<ul class="doc-list">
<li ng-repeat="docs in casedocs">
X <a ng-href="#" ng-click=loadDocument(docs.Doc_Path)>{{docs.Description}}</a>
</li>
</ul>
there are a bunch of extra empty rows in the list. What can I do to stop this behavior? See the two images to show what it looks like correct and what it looks like when wrong:
I checked your code, it worked fine (in Chrome and FF at least), no additional/empty rows were created after addition of arbitrary characters in front of the link. Whatever the problem is it doesn't seem to be Angular's fault. Anyway, here's the code:
HTML:
<div ng-app="myApp" ng-controller="myCtrl">
<ul class="doc-list">
<li ng-repeat="docs in casedocs">
Xasdf {{docs.description}}
</li>
</ul>
</div>
Controller:
angular.module("myApp", []).controller("myCtrl", ["$scope", function($scope){
$scope.casedocs = [
{
description:"One",
Doc_Path:"someUrl"
},
{
description:"Two",
Doc_Path:"someUrl"
},
{
description:"Three",
Doc_Path:"someUrl"
}
];
$scope.loadDocument = function(url){
alert(url);
}
}]);
I am posting this answer in case someone else has this issue. The service was apparently returning null records that were filtered by both the browser when looking what the service returned and Postman as well. We fixed the service to not return those null records and the problem resolved itself.
I am trying to work out ng repeat animation when I add/remove items from two different arrays one after another but it doesn't seem to work really smoothly on chrome-it works on firefox. Here is the following example codes:
template.html
<ul>
<li ng-repeat='item1 in arr1' class="repeated-item">
<span>{{ item1 }}</span>
</li>
</ul>
index.html
<div>
<div ng-include='template.html'></div>
<ul>
<li ng-repeat='item2 in arr2' class="repeated-item">
<span>{{ item2 }}</span>
</ul>
</div>
I notice animation works quite well for outside repeat except ng-included template. Hope you guys can help to figure out this.
You didn't close the <div ng-include='template.html'> tag properly. Add the closing tag </div>.
Hi all you experts out there.
My testing area: http://plnkr.co/edit/ddJT1e4a8L5NTSIVNTk7
I am trying to visualize hierarchical data in a tree-form with Angular, even though i'm using some samples to aid me in my quest (like http://jsfiddle.net/alalonde/NZum5/ and http://jsfiddle.net/brendanowen/uXbn6/8/) i fail.
As soon as i place the recursive element ng-include inside the ng-repeat in side the template it self, the memory usage of its browser-window goes through the roof and effectively hangs the browser. But the available tree-sample i could find are doing just that.
What am i missing?
You need to use the same variable name in the template. The current node is called node in the controller then child in the template.
This cause the template to render the same node over again.
It works fine if you use the same variable name :
<li ng-repeat="node in node.children" ng-include="'node.html'"></li>
See it in action here : http://plnkr.co/edit/mjfdSEDcMK8kGCRjS6V6?p=preview
If anyone here wants to avoid having the extra ng-repeat outside of the template (where it kind of includes stuff from the template anyway), here's a fiddle showing how to do it:
http://jsbin.com/hokupe/1/edit
Also here's a blog post and a 10-15 minutes video on how it works:
http://gurustop.net/blog/2014/07/15/angularjs-using-templates-ng-include-create-infinite-tree/
Sample Code:
<script type="text/ng-template" id="treeLevel.html">
<ul>
<li ng-repeat="item in items">
<input type="checkbox"
name="itemSelection"
ng-model="item._Selected" />
{{item.text}}
<div ng-include=" 'treeLevel.html'"
onload="items = item.children">
</div>
</li>
</ul>
</script>
<div ng-include=" 'treeLevel.html' "
onload="items = sourceItems">
</div>
In AngularJS, to simply show a field through an a tag, I would do in this way:
<div ng-show="aField">Content of aField</div>
<a ng-click="aField=true">Show aField</a>
until here, no problem.
I would like now to put more buttons and fields so that, when I click on A it shows the content of A, then when I click on button B, content of A disappears and content of B appears.
How can I do this? Thank you.
UPDATE
Thank you everyone for your solutions, they works! Now, I am doing a template for every content of and because I have much data to show but all in the same structure.
Here the index.html
<div ng-model="methods"
ng-include="'templateMethod.html'"
ng-repeat = "method in methods">
here the script.js:
function Ctrl($scope) {
$scope.methods =
[ { name: 'method1',
description: 'bla bla bla',
benefits: 'benefits of method1',
bestPractices : 'bestPractices',
example: 'example'},
{ name: 'method2',
description: 'bla bla bla',
benefits: 'benefits of method2',
bestPractices : 'bestPractices',
example: 'example'} ];
}
and here the templateMethod.html:
<table>
<tr>
<td>
<div ng-show="toShow=='{{method.name}}Field'">
<h3>{{mmethodethod.name}}</h3>
<p>
<strong>Description</strong>
{{method.description}}
</p>
<p>
<strong>Benefits</strong>
{{method.benefits}}
</p>
<p>
<strong>Best practices</strong>
{{method.bestPractices}}
</p>
<p>
<strong>Examples</strong>
{{method.example}}
</p>
</div>
</td>
<td class = "sidebar">
<ul>
<li><a ng-click="toShow='{{method.name}}Field'" class="{{method.name}} buttons">{{method.name}}</a></li>
</ul>
</td>
</tr>
</table>
It works!
But: if I click the first button and then the second one, the content of the first button do not disappear, it appears under the content of the first button...
Problem with the repetition?
Thanks
It might be better to handle more complex logic in the controller, but in general think about the content of the directive strings as normal js:
<div ng-show="aField">Content of aField</div>
<div ng-show="bField">Content of bField</div>
<a ng-click="aField=true; bField=false">Show aField</a>
<a ng-click="aField=false; bField=true">Show bField</a>
Or use ng-show in concert with ng-hide:
<div ng-show="aField">Content of aField</div>
<div ng-hide="aField">Content of bField</div>
<a ng-click="aField=true">Show aField</a>
<a ng-click="aField=false">Show bField</a>
In the former strategy, nothing shows upon page load. In the latter, the bField content shows by default. If you have more than two items, you might do something like:
<div ng-show="toShow=='aField'">Content of aField</div>
<div ng-show="toShow=='bField'">Content of bField</div>
<div ng-show="toShow=='cField'">Content of cField</div>
<a ng-click="toShow='aField'">Show aField</a>
<a ng-click="toShow='bField'">Show bField</a>
<a ng-click="toShow='cField'">Show cField</a>
I'm guessing that you have a list of items and want to show each item content. Something an accordion component does.
Here is a plunker that shows how you could do it: http://plnkr.co/edit/UTf3dEImiDReC89vULpX?p=preview
Or if you want to display the content on the same place (something like a master detail view) you can do it like this: http://plnkr.co/edit/68DJHL582oY4ecSiiUdE?p=preview
simply use one variable which content is visible. http://jsfiddle.net/gjbw7/
<a ng-click="show='a'">Show aField</a>
.
<div ng-show="show=='a'">Content of aField</div>
I would recommend to create a service in case your fields belong to different controllers.
Service:
App.factory('StateService', function() {
return {
openPanel: ''
};
});
Injecting the service in a Controller:
App.controller('OneCtrl', function($scope, StateService) {
$scope.stateService = StateService;
});
Finally using it a view:
<a ng-click="stateService.openPanel='home'">Home</a>
<div ng-show="stateService.openPanel == 'home'">Content of Home</div>
Demo: http://jsfiddle.net/codef0rmer/BZcdu/
Try this way.
<div>{{content}}</div>
<a ng-click="content='a'">Show aField</a>
<br>
<a ng-click="content='b'">Show bField</a>
<br>
<a ng-click="content='c'">Show cField</a>
<br>
<a ng-click="content='d'">Show dField</a>
<br>
<a ng-click="content='e'">Show eField</a>
<br>
<a ng-click="content='f'">Show fField</a>
Take a look at the ng-switch directive.
<div ng-switch="aField">
<div ng-switch-when="someValue1">
HTML content that will be shown when the aField variable value is equal to someValue1
</div>
<div ng-switch-when="someValue2">
HTML content that will be shown when the aField variable value is equal to someValue2
</div>
<div ng-switch-default>
This is where the default HTML content will go (if aField value is not equal to any of the ng-switch-when values)
</div>
</div>