Slice ng-repeat with AngularJS - javascript

An easy question from a noob in Angular.
I have my ng-repeat like this:
ng-repeat="f in drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR]
and I want to slice the last record because it's alway empty and it comes like that from the WS but I dont know how to achive this in AngularJS.

Inside ng-repeat you have available a variable $last.
example
<div ng-repeat="item in [1,2,3,4]">
<div ng-if="!$last">{{item}}</div>
</div>
See more https://docs.angularjs.org/api/ng/directive/ngRepeat

Use the limitTo filter.
ng-repeat="f in drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR] | limitTo:-1"
Alternatively, just show the last item in the list.
<div data-ng-bind="drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR][drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR].length-1]"
</div>
Might I suggest that you do all that concatenation in the Controller? If you do it on the View side, it's going to execute every digest.

Related

AngularJS: ng-click for ng-repeat to get all data at once

I have my simple ng-repeat:
<div ng-repeat="x in names">
<h4>{{x.productid}}</h4>
<h4>{{x.newquantity}}</h4>
<h4>{{x.total}}</h4>
<button ng-click="addInfoAboutOrder(x)">Add Info</button>
</div>
and AngularJS function:
$scope.addInfoAboutOrder = function(x) {
$scope.productId = x.productid;
$scope.productQuantity = x.newquantity;
$scope.total = x.total;
$http.post("api/setOrdersInfo" + "/" + $scope.productId + "/" + $scope.productQuantity + "/" + $scope.total)
}
At the moment it is working. However, ng-repeat prints out button as many times as there are data(from 1 to 50). Of course this can be done by adding a simple filter, but it does not solve my problem. The biggest problem is it adds only one row in the table in the database. My problem is I can't make one
<button ng-click="addInfoAboutOrder(x)">Add Info</button>
to handle all my data in ng-repeat. I would like by one button click to add as many data in database as there are in ng-repeat.
Move the button outside of the ng-repeat:
<div ng-repeat="x in names">
<h4>{{x.productid}}</h4>
<h4>{{x.newquantity}}</h4>
<h4>{{x.total}}</h4>
</div>
<button ng-click="addInfoAboutOrder(names)">Add Info</button>
Then pass in names instead of x and iterate over names in order to get all the data out of it, making a $http request for each iteration (do note that this will most likely cause performance issues for large data sets, so you should try to find a better solution to do what you want):
$scope.addInfoAboutOrder = function(names) {
for (var i = 0; i < names.length; i++) {
$http.post("api/setOrdersInfo" + "/" + names[i].productid + "/" + names[i].newquantity + "/" + names[i].total);
}
}

Click items in an ng-repeat to fill another list

I have a working plunker where you select a thing from a dropdown and it displays data. I would like to be able to click one of those items and it to fill another list below. with other data. I know of ng-click and thats what I am using currently to just pop up an alert with the data I want to be in the list.
This is the section in question:
<div>
<select ng-options="post as post.id for post in allPosts" ng-model="selectPost" ng-change="select()">
<option value="">--select--</option>
</select>
<input type="text" ng-model="searchText" ng-change="search()" />
<ul>
<li data-ng-repeat="item in records | orderBy:'email':reverse" ng-click="moreInfo(item)">
{{item.email}}
</li>
</ul>
</div>
Ideally I want a list like what is in the popup something like:
Email: 'email...'
Name: 'name...'
Body: 'body...'
Like what is in the popup, but to show up below the list of things displayed from choosing the dropdown. (on my webpage it will be over to the right so I am not concerned about formatting, just how to do it). But I DO NOT want the the list to show up if I don't click on an option.
Plunker here.
edit: I am beginning to think maybe an ng-show will do the trick in some fashion, yet, I still do not know how I would pass the data down to the list.
Create a div that will be visible when a message variable is available.
<div ng-show="message">
{{ message }}
</div>
and in your controller, assign the contents for the moreInfo to a $scope.message:
$scope.moreInfo = function(id) {
$scope.message = "Email: " + id.email + "\nName: " + id.name + "\nBody: " + id.body;
};
Here's an updated plunker.
I edited your plunker , hope that is what you wanted.. and it's better for you to use controller as syntax article and you should looki into styleguide too i like this one by John Papa styleguide
It's actually quite straightforward:
First, set your new text to a scope value on click:
$scope.moreInfo = function(id) {
$scope.curResults = "Email: " + id.email + "\nName: " + id.name + "\nBody: " + id.body
//alert("Email: " + id.email + "\nName: " + id.name + "\nBody: " + id.body);
};
Then, simply assign this value to another div:
<div ng-show="curResults">{{curResults}}</div>
Then, whenever you click on the results, curResults is updated and shown in that div.
ng-show="curResults" makes sure the div is only shown when there's a value set to curResults.

Reusable directive with dynamic ng-repeat item name

I have created reusable directive something like dropdown but dropdown open in modal which is working good.
my directive looks like this
<p-select items="deptStations" header-text="Select " text="Select departure..." text-icon="ion-chatbubble-working" text-field="City_Name_EN" text-field2="City_Code" value-field="City_Code" ng-model="deptStation.value">
</p-select>
<p-select items="arrStations" header-text="Select " text="Select arrival..." text-icon="ion-chatbubble-working" text-field="D.City_Name_EN" text-field2="D.City_Code" value-field="D.City_Code" ng-model="arrStation.value">
</p-select>
My directive html is
<ion-content>
<div class="list">
<label ng-repeat="item in items | filter:search" class="item item-text-wrap" ng-click='validateSingle(item)'>
{{item[textField]}} {{textField2 !== '' ? " (" + item[textField2] + ")" : ""}}
</label>
</div>
</ion-content>
Now my issue is when JSON is 1 level it will work as below
[{City_Name_EN:'Abu Dhabi', City_Code:'AUH' },
{City_Name_EN:'Alexandria',City_Code:'HBE' }]
But if I have 2 level JSON than it will not work
[{D:{City_Code:'AMM',City_Name_EN:'Amman'},
D:{City_Code:'BKK',City_Name_EN:'Bangkok'}}]
So how can make this part dynamic {{item[textField]}}
My plunkr http://plnkr.co/edit/GxM78QRwSjTrsX1SCxF7?p=preview
With this kind of dynamic expression of yours, it is always better to have directive consider only a specific contract provided as view model. If the directive consumer has a different data format it should be upto that component to provide the contract that directive needs, it can just map the data to the view model that directive expects. This way you can keep things clean, that would be my opinion.
Now to work around your issue you would need to do a trick to evaluate the multilevel property against an object. You can use $scope.$eval to evaluate any dynamic expression against the scope object. example you can evaluate a dynamic property evaluation of prop1.prop2.prop3 on a scope property item by doing $scope.$eval("prop1.prop2.prop3", item) or $scope.$eval("item." + "prop1.prop2.prop3")
So in your directive:
Added a scope function to get the item text and value:
$scope.getItemName = function(field, item){
//here "this" represents the current child scope of ng-repeat
return $scope.$eval(field, item);
//return this.$eval("item." + field);
}
and
$scope.validateSingle = function(item) {
$scope.text = $scope.$eval($scope.textField, item) + ($scope.textField2 !== '' ? " (" + $scope.$eval($scope.textField2, item) + ")" : "");
$scope.value = $scope.$eval($scope.valueField, item);
...
Update your template to get respective text:
<label ng-repeat="item in items | filter:search" class="item item-text-wrap" ng-click='validateSingle(item)'>
{{getItemName(textField, item)}} {{textField2 !== '' ? " (" + getItemName(textField2, item) + ")" : ""}}
</label>
Plnkr

ng-class not responding to change in model in Angular?

Having searched extensively, got some help from A ternary in templates and getting partially functional results, I'm 99% sure I'm doing it 99% right, but...obviously not completely, so I'm here.
The basic HTML structure:
<ul>
<li class="week-row" ng-repeat="week in weeks" id="{{$index}}">
<ul class="tiles" ng-class="{ 'expanded': week.isOpen, 'hidden': !week.isOpen }">
<li class="day-tile"
ng-class="{'active': (activeDay == $parent.$index + '-' + $index) }"
id="{{$parent.$index + '-' + $index}}"
ng-repeat="day in week.days"
ng-click="fn2({ week: $parent.$index, day: $index })">
<!-- moved ng-class to here, and it works? -->
<div>some stuff in here</div>
</li>
</ul>
</li>
</ul>
The stuff in the controller that sits above it:
$scope.activeDay = null;
$scope.fn1 = function() { $scope.activeDay = '0-0'; }; // this works, and sets the first one active
$scope.fn2 = function(data) { $scope.activeDay = data.week + '-' + data.day; }; // this sets the first one not active, but none of the others go active
I'm trying to set one of the nested list items to be active, based on its indexes in the nested arrays by using the $parent.$index and $index as a string, joined by '-'.
What's throwing me off is that console.logging $scope.activeDay, data.week + '-' + data.day, and both == and === comparisons come out exactly as I would expect, (the same strings, true, true) and it works on initial load when I set activeDay to '0-0', so I'm clearly missing something in my binding or...?
After finding this: https://egghead.io/lessons/angularjs-the-dot - I tried setting it up as an object so I couldn't get into some weird isolate scope nonsense: $scope.tiles = { activeDay: null }; and then setting that property from my functions, to no avail.
Why does setting it initially work, while changing it later does not? Is this improper binding of classes or...?
I also tried it with
class="day-tile {{activeDay == $parent.$index + '-' + $index ? 'active' : ''}}"
and that works initially, but breaks afterwards...
Your help is much appreciated!
UPDATE:
After moving ng-class="{'active': (activeDay == $parent.$index + '-' + $index) }" onto the div inside the ng-repeated .day-tile li, it works fine.
Any ideas why this might be?
From the info you provided I have this working jsFiddle.
I removed the classes you were hard coding to true and stuck them in class="". The classes you were evaluating expressions for i put in ng-class="".
I attached your functions to $scope so ng-click could find them. So $scope.fn2 rather than var fn2.
Without knowing more details, I would say this should fix your problem.
Code Changes:
controller:
$scope.activeDay = null;
$scope.fn1 = function() { $scope.activeDay = '0-0'; };
$scope.fn2 = function(data) { $scope.activeDay = data.week + '-' + data.day; };
partial:
<ul class="tiles" ng-class="{'expanded' : week.isOpen, 'hidden' : !week.isOpen}">
<li class="day-title"
ng-class="{'active': (activeDay == $parent.$index + '-' + $index)}"
id="{{$parent.$index + '-' + $index}}"
ng-repeat="day in week.days"
ng-click="fn2({ week: $parent.$index, day: $index })">
//put expression here so you can see the list item
{{week.day}}
</li>
</ul>

ng-repeat don't show last piece of text

I have a list of answers that I would like to separate by a comma, but I do not want the last comma to show - how can I do this using ng-repeat and !$last? This is the html I have so far (which is not showing the entire last answer):
<h3 ng-repeat="answer in correctAnswers" ng-show="!$last">
{{answer + "," + " " }}
</h3>
I would recommend not using a separate span and toggling visibility, but use something closer to what you have already attempted:
<h3 ng-repeat="answer in correctAnswers">
{{answer + ($last ? '' : ',')}}
</h3>
No extra directives to be processed, just simple boolean logic w/ concatenation of a string
For convenient, you can try this
<h3 ng-repeat="answer in correctAnswers">
{{answer}}<span ng-show="!$last"> + "," + " "<span>
</h3>

Categories