Render a collection with different classes one time in two - angularjs

I am a beginner using AngularJS.
I would like to render a collection in my HTML code, with a specific directive: one item at left, the following one at right, the third one at left etc...
<div ng-repeat="Model in Collection">
<!-- The HTML i need for even iterations -->
<div class="col-xs-2.col-sm-2.col-md-2.col-lg-2.col-xs-offset-2.col-sm-offset-2.col-md-offset-2.col-lg-offset-2">
<img alt="Player" src="{{Model.avatar}}" popover-placement="left">
</div>
<!-- The HTML i need for odd iterations -->
<div class="col-xs-2.col-sm-2.col-md-2.col-lg-2.col-xs-offset-8.col-sm-offset-8.col-md-offset-8.col-lg-offset-8">
<img alt="Player" src="{{Model.avatar}}" popover-placement="right">
</div>
</div>
What is the better way to do that ?

You can take advantage of ng-class-odd and ng-class-even to declare the class of the divs.
<div ng-repeat="Model in Collection">
<div ng-class-even="'col-xs-2.col-sm-2.col-md-2.col-lg-2.col-xs-offset-2.col-sm-offset-2.col-md-offset-2.col-lg-offset-2'"
ng-class-odd="'col-xs-2.col-sm-2.col-md-2.col-lg-2.col-xs-offset-8.col-sm-offset-8.col-md-offset-8.col-lg-offset-8'">
<img alt="Player" src="{{Model.avatar}}" ng-class-even="'left'" ng-class-odd="'right'">
</div>
</div>

Related

Can one dynamically insert ng-repeats into an angular app

ng-repeat is very useful, however I am finding my application needing dynamic insertion of ng-repeats
Is it possible to insert html dynamically into the view from one of the javascript controllers?
Alright; my specific use-case is the following:
I have a nested ng-repeat in my view:
<div id="sunti_grid">
<div class="sunti_contain" ng-repeat="sunti in showable_suntis track by $index">
<div class="individual_sunti" ng-click="descendents(sunti.short_id); update_ancestor(sunti);" ng-dblclick="update_ancestor(null);" ng-class="{active_sunti : actively_selected_sunti == sunti.short_id}">
<div class="sunti_content" ng-bind="sunti.content"></div>
<div class="sunti_tags" ng-bind="sunti.tags"></div>
<div class="sunti_author" ng-bind="sunti.author"></div>
<div class="sunti_shortid" ng-bind="sunti.short_id"></div>
<div class="sunti_ancestor" ng-bind="sunti.ancestor"></div>
<div class='rating_contain' ng-show="is_user_authenticated">
</div>
</div>
<div class="sunti_reply_carriage_wrapper" ng-if="descendents(sunti.short_id).length > 0">
<div class="sunti_reply_carriage">
<div class="individual_sunti reply_carriage_sunti" ng-repeat="descendent in descendents(sunti.short_id)">
<div class="sunti_content" ng-bind="descendent.content"></div>
<div class="sunti_tags" ng-bind="descendent.tags"></div>
<div class="sunti_author" ng-bind="descendent.author"></div>
<div class="sunti_shortid" ng-bind="descendent.short_id"></div>
<div class='rating_contain' ng-show="is_user_authenticated">
</div>
</div>
</div>
</div>
</div>
</div>
So basically, sunti_grid has an ng-repeat that makes a long list of suntis and each sunti can have descendents. The descendents appear in a "carriage" that manifests immediately below the given sunti.
Now, when a user clicks on a descendent (kinda like a magically-appearing row-drop-down) I want to inject yet another carriage.
Here is a simple schematic to illustrate the feature so far:
[sunti]
[sunti]
[sunti]
[d][d][d][d][d]..
[sunti]
[sunti]
[d][d][d][d][d][d]...
Now I want to be able to inject another carriage of descendents for each descendent-row.. kinda like
[sunti]
[sunti]
[d][D][d][d][d][d]...
[D2][D2][D2][D2]...
[D3][D3][D3]...
so clicking on [D] would make the [D2] row appear, and clicking on one of the [D2]s would make row [D3] appear...
The only thing I can think of so far is to use the controller to inject a new ng-repeat for every new descendent row.
Suggestions welcome. What would be a good (read: maintainable) way of dynamically inserting ngRepeats?

ng-repeat + ng-switch: how to use correctly?

Premise: I've seen several similar questions. But I can't really figure out how to solve my doubt.
I have an array of objects:
$scope.messages = [obj1, obj2, ...];
where each object has the following structure:
{
id: <int>,
printOnlyFirst: <boolean>,
text1: <string>,
text2: <string>
}
where text1 / text2 are conditionally printed (in real time through track by) according to printOnlyFirst.
<div id="container">
<div ng-switch="printOnlyFirst" ng-repeat="message in messages track by message.id">
<div ng-switch-when="true" class="text1"> <!-- case 1 -->
{{message.text1}
</div>
<div ng-switch-when="false" class="text2"> <!-- case 2 -->
{{message.text2}
</div>
</div>
</div>
I think this code is fine.
However I noticed that
<div ng-switch="printOnlyFirst" ng-repeat="message in messages track by message.id">
is printed for each single element of the ng-repeat loop, together with it's content (either case 1 or 2).
Is this normal?
Is there a better solution to avoid such DOM overhead?
From https://docs.angularjs.org/api/ng/service/$compile#-priority-:
Directives with greater numerical priority are compiled first.
ngSwitch executes at priority 1200 while ngRepeat executes at priority 1000, which isn't the order you need.
You'll have to use a nested component (a div for example):
<div id="container">
<div ng-repeat="message in messages track by message.id">
<div ng-switch="message.printOnlyFirst">
<div ng-switch-when="true" class="text1"> <!-- case 1 -->
{{message.text1}
</div>
<div ng-switch-when="false" class="text2"> <!-- case 2 -->
{{message.text2}
</div>
</div>
</div>
</div>
Don't forget to switch on message.printOnlyFirst rather than printOnlyFirst.

How can I render two angular.js views on the same page?

If I have two <div ng-view></div> elements on the same page, angular.js only uses the first one. I am looking to have two templates (with two controllers and two partials) rendered on the same page, how do I do that? The code below does not work but I'd like to have something along these lines.
<div class="row">
<div class="large-6 small-12 columns">
<div ng-controller="SitesHomeCtrl" >
<div ng-view>
</div>
</div>
</div>
<div class="large-6 small-12 columns">
<div ng-controller="UsersMeetCtrl" >
</div>
</div>
</div>
ui-router is the best option but if you are going with $routeProvider, you could use ng-include (with ng-show/ng-hide) or ng-switch to achieve the same.
I imagine you're probably going to want to look at ui-router in place of angular's router at this point, as angular's router does not support multiple ng-view elements.

AngularJS using ng-switch without wrapper div

I would like to use ng-switch because I do not want the other elements that I do not want to show to be part of the DOM. That is why i did not use ng-hide/ng-show. In the example below, I would like to only have the span tag be in the DOM without the div wrappers from the ng-switch. What is the best way to accomplish this?
<div ng-switch on="user">
<div ng-switch-when="true">
<span>One</span>
</div>
<div ng-switch-when="false">
<span>Two</span>
</div>
</div>
You can use the ng-switch directive as a custom element and not specify the div in the first place. For example:
<ng-switch on="user">
<span ng-switch-when="true">One</span>
<span ng-switch-default>Two</span>
</ng-switch>
Here is a plunker to play around with: http://plnkr.co/edit/zni6raUWOguhQh9jDiY3
the solution provided by #ChrisAuer this still creates a wrapping element.
AFAIK you'd have to use a custome directive. You may want to use angular-ui if
<div ui-if="user">
<span>One</span>
</div>
<div ui-if="!user">
<span>Two</span>
</div>
Probably, in your case, you'd be fine using ng-show or ng-hide which only hide(display:none) the element - they don't remove it form the DOM.
<div ng-show="user"> <!-- same as ng-hide="!user" -->
<span>One</span>
</div>
<div ng-hide="user"> <!-- same as ng-show="!user" -->
<span>Two</span>
</div>
I would say use ng-if, like this:
<div>
<div ng-if="user==true">
<span>One</span>
</div>
<div ng-if="user==false">
<span>Two</span>
</div>
</div>
you can use <span> to prevent your html layout changing
because <span> is not like <div>, it won't take up any space.
<span ng-switch="user">
<span ng-switch-when="true">One</span>
<span ng-switch-default>Two</span>
</span>

AngularJS: data-ng-model & data-ng-hide/show

My index.html page is like as follows:
<div id="sidepanel" data-ng-controller="ListCtrl">
<li data-ng-repeat="record in records">
{{record.id}}
<input type="checkbox" data-ng-model="addwidget">
</li>
</div>
<div id="main">
<div data-ng-view></div>
</div>
for this data-ng-view i have another page recordlist.html in that i have following code:
<div data-ng-controller="ListCtrl">
<ul class="design">
<li data-ng-repeat="record in records">
<div data-ng-switch data-on="record.category">
<div data-ng-switch-when="reporting1">
<div id="{{record.id}}" data-ng-show="addwidget">{{record.description}}</div>
</div>
<div data-ng-switch-when="reporting2">
<div id="{{record.id}}" data-ng-hide="addwidget">{{record.description}}</div>
</div>
</li>
</ul>
</div>
My question is i want to show the first div when i check the checkbox & when i uncheck it i want to show the second div.When both of the data-ng-model & data-ng-hide/show are on the same page then it works fine but in my case it present on two different pages.
Is it correct ? How can i implement this. Need Help.Thanks.
The problem is that you are setting addwidget in the first controller, but is trying to use it in the second. Controllers are not singletons.
So, in this situation:
<div id="sidepanel" data-ng-controller="ListCtrl">
...
</div>
<div id="main">
<div data-ng-view>
<div data-ng-controller="ListCtrl">
</div>
</div>
</div>
You got two separated controllers and scopes. And you are setting addwidget in the first trying to read in the second.
You can either bind it to the root scope $root.addwidget or use a service share to the states.
As you have many records, binding directly to root is a problem, as all of them are going to share the same state. So you gonna need an object in the rootScope and bind the option by id $root.addwidget[record.id]. Made a pretty simplified modification here.

Resources