AngularJS Directive - - angularjs

I am trying to make a schedule. The object that I receive from my API is as follows:
schedule : {
id,
name,
shifts : []
}
// each shift is
shift : {
id,
schedule_id,
user,
tasks: []
}
// each task is
task: {
id,
shift_id,
time_start,
time_end
}
My HTML currently is (please see image below for a snapshot of what it looks like right now)
<div class="schedule">
<!-- This is the time of the day column, such as 10:00, 11:00 -->
<div id="clock"></div>
<div class="shifts">
<div class="shift" ng-repeat="shift in schedule.shifts">
<!-- The user assigned to this shift -->
<div class="user" ng-bind="shift.user"></div>
<!-- This is the time cells in 15min interval -->
<div class="cells">
<!-- Not going into detail, but this creates the cells
<div class="cell" ng-repeat="cell in cells"></div>
</div>
<!-- The tasks -->
<div class="tasks">
<div class="task" ng-repeat="task in shift.tasks"></div>
</div>
</div>
</div>
</div>
Right now, since the tasks are placed in their own container, then to bring the task down the right start time, I basically calculate how much the task.time_start is different than the start of the day, and then convert that to a CSS of top: $some-pixel (by multiplying time difference by the height of each cell).
I'd like to instant have these tasks bind to the cells. But how can I do that? The tasks are in an array inside shift.tasks, and I cannot figure out how I could loop through them while I am creating the cells.
Or maybe what I am doing is right?
Edit
The only thing that I can think of is having the ng-repeat inside the cell as well, and use ng-if
<div class="cells">
<div class="cell" ng-repeat="cell in cells">
<div class="task" ng-repeat="task in shift.task" ng-if="task.time_start = cell.time_start"></div>
</div>
</div>

Sounds like you need to loop the 15-min intervals instead of (or combined with) tasks. Create a cell for each, and then check the tasks and if there is a task present at that time - fill the cell.
EDIT
So yeah, basically, what you wrote in your edit - so render both the empty and non-empty cells and fill in the needed ones.
Something like this:
<div class="cells">
<div class="cell" ng-repeat="cell in cells">
<div class="subcell" ng-repeat="subcell in subcells"> <!-- 4 subcells -->
<div class="task" ng-repeat="task in shift.task" ng-if="task.time_start = subcell.time_start"></div>
</div>
</div>
</div>
I used ng-if="task.time_start = subcell.time_start", but you can modify it however you want, maybe like cell.time_start + subcellIndex * 15, etc...

Related

Data duplicating issue with JSON

I have included the code in http://codepen.io/sajoambattu/pen/MbezNa
I have 3 divs in which each div includes color selection, Memory and call plans. The call plans data is there after every device details(after the table).
All the data are depending on 3 JSONs. The color selection and Memory data is coming from devices JSON and call plans data is coming from callplans JSON. I have another JSON(planMapping) for mapping the device and call plan. All JSON's I have included in the JS file.
My requirement is based on the user selection of color and memory, respective call plans should display. Now the content is displaying, but the problem I'm facing is it's displaying the same content in all three sections(Apple, Samsung and Sony).
Issue Example:
Click iPhone 6s plus tab from the apple section and click on 32GB memory and then click any color, now iPhone 6s plus call plans will display. The problem is the same iPhone 6s plus call plans data is getting displayed in all other sections as well.
Any help would be appreciated.
I have updated your code....
http://codepen.io/anon/pen/dOpdXr
Changes :
HTML:
<div class="planDetails" ng-repeat="data in x.callPlanArr">
and also moved </div> of <div class="device_overview {{x.memory}}-{{x.presales_name.split(' ').join('-').replace('(','').replace(')','')}}" ng-repeat="x in v | orderBy:'memory'" ng-show="$first"> moved to end of the modified div.
JS:
item.callPlanArr = []; //at line 5770
and
item.callPlanArr.push($scope.callplanList.callplans[x]); //5784
Make following change to meet your requirement:
Shift div with class="callPlans" inside div with class="device_overview"
Here is the modification:-
<div class="device_overview {{x.memory}}-{{x.presales_name.split(' ').join('-').replace('(','').replace(')','')}}" ng-repeat="x in v | orderBy:'memory'" ng-show="$first">
<div class="device_detail">
<p>{{x.presales_vendor}}</p>
<h3>{{x.presales_name}}</h3>
<p>{{result}}</p>
</div>
<div class="color">
<div class="color-name">
<p>Choose color:</p>
<span ng-repeat="data in x.variants" class="{{data.s_code}}-{{x.presales_name.split(' ').join('-')}}" ng-show="$first">{{data.colour}}</span>
</div>
<div class="color-code" ng-repeat="data in x.variants" ng-click="changeImg(((data.s_code+' ')+(x.presales_name)).split(' ').join('-').replace('(','').replace(')',''));showPlan(x,data.s_code); showStock(data.s_code);" style="border-color:{{data.colour_code}};background-color:{{data.colour_code}}">{{data.colour_code}}</div>
</div>
<div class="callPlans" ng-if="device_class == x.device_class">
<div class="planDetails" ng-repeat="data in callPlanArr">
<div class="data">
<p>Data</p>
<h3>{{data.plan.data_allowance}}GB</h3>
</div>
<div class="minute">
<p>Minutes</p>
<h3>{{data.plan.call_allowance}}</h3>
</div>
<div class="text">
<p>Texts</p>
<h3>{{data.plan.text_allowance}}</h3>
</div>
<div class="upfront">
<ul>
<li ng-show="data.upfront != ''"><p>£{{data.upfront}}</p>up front</li>
<li><h2>£{{data.plan.rental}}/mth</h2></li>
</ul>
</div>
</div>
</div>
</div>
and add following line in $scope.showPlan function() of your controller
$scope.device_class = item.device_class;

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?

AngularJS data-ng-hide puts blank spaces

It looks as though data-ng-hide works as expected except that it puts a space where the value would be shown. Is there a way to surpress that space so the values which should be shown are shifted to the right. For instance my loop has three people in it, but on the third person will be shown. The name for that person is to the far right rather than the first column on the left. I can't use data-ng-if as it removes values from the array.
This is the code:
<div class="row">
<label class="col-md-3" style="text-align: center">Checked Out to:</label>
<div class="col-md-8" ng-repeat="rows in chunkedData">
<div class="col-xs-4" ng-repeat="route in rows">
<span data-ng-hide="!route.checkedOut">{{route.user.firstName}} {{route.user.lastName}}</span>
</div>
</div>
</div>
This is the normal behavior: You're repeating a <div> that has the class "col-xs-4".
The ng-hide is inside it, meaning that for each route in rows, you'll display a column with or without text in it.
Try this instead :
<div class="col-xs-4" ng-repeat="route in rows | filter:{checkedOut:true}">
{{route.user.firstName}} {{route.user.lastName}}
</div>
AngularJS's documentation on ngRepeat and filters could also help you to better understand filters.

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.

Render a collection with different classes one time in two

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>

Resources