Angularjs: change object property of specific index of nested ng-repeat - javascript

I've nested ng-repeat like this:
<div ng-repeat="(dayOfWeek, time) in uiHoursOfOperation track by $index" ng-init="daysOfWeekIndex=$index">
<div class="" ng-repeat="openCloseSet in time.uiDayMs track by $index">
<md-input-container>
<md-select ng-model="openCloseSet[0]" ng-init="openTime = openCloseSet[0]">
<md-option ng-repeat="uiTime in time.avaiableTime" ng-value="uiTime.msValue">
{{::uiTime.display}}
</md-option>
</md-select>
</md-input-container>
<md-input-container ng-if="$index === 0">
<md-button ng-click="addSplitHours(time.uiDayMs ,$index +1, time)">
Add
</md-button>
</md-input-container>
</div>
</div>
On clicking the Add button. It creates a new block of time.uiDayMs.
Here is the add function:
$scope.addSplitHours = addSplitHours;
function addSplitHours(index, time) {
var newOpen = time.uiDayMs[time.uiDayMs.length - 1][1] + 900000;
time.uiDayMs.push([newOpen, newOpen + 900000 * 4]);
var closingtimeStarts = closingTime + 900000;
var closingtimeEnds = avaiableClosingTimes[avaiableClosingTimes.length - 1].msValue;
for (
var msValue = closingtimeStarts;
msValue <= closingtimeEnds;
msValue += 900000
) {
time.avaiableTime.push({
msValue: msValue,
display: moment(msValue)
.utc()
.format("h:mm A")
});
}
}
You can see I'm taking the next index number but unable to use it.
So my main question is how can I make the time.avaiableTime.push to only that specific index? Currently, It changes on each time.avaiableTime but I wanted to push on that specific index only.

Related

Sum array inside array elements and bind it in html inside an ngFor loop div in angular8

*)Please check out this 2 images in this i have a stock-shift array it's length is 2 and inside every
array i have another array, in the inside array i have to sum the elements of the quantity
*)check my html code and ts file and help me with the solution
*)Check the third image Ui there I need to bind sum value before the quantities like that for every
tile (box) i need to get different value but it is updating last value in all tiles (boxes)
html
====
<div *ngFor="let data of dataSource; let i = index;">
<!-- Stockshift card -->
<mat-card *ngIf="type === 'shift'" class="mb-3 card" (click)="addParams(data,data?.invoiceNumber,5, i)">
<mat-card-content class="p-2" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="space-between">
<div><span [ngClass]="{'text-success' : data?.isSyncSuccess, 'text-danger' : data?.isSyncFailed, 'text-warning': (!data?.isSyncFailed && !data.isSyncSuccess)}"><b>#{{ data?.invoiceNumber }}</b></span></div>
<div><span [ngClass]="{'text-success' : data?.isSyncSuccess, 'text-danger' : data?.isSyncFailed, 'text-warning': (!data?.isSyncFailed && !data.isSyncSuccess)}"><b>{{ data?.entryDate | date: 'dd MMM yyyy'}}</b></span></div>
</div>
<span class="text-dark pt-2 card-content">
<span>{{(data?.type === 'TO') ? 'Sent' : 'Received'}}</span>
<span *ngIf="data && data?.productList[0]?.quantity < 1"> product <span class="text-primary">({{data?.productList[0]?.quantity}} Quantity)</span> {{(data?.type === 'TO') ? 'to' : 'from'}} </span>
<span *ngIf="data && data?.productList[0]?.quantity > 1"> products <span class="text-primary">({{totalProductList}} Quantities)</span> {{(data?.type === 'TO') ? 'to' : 'from'}} </span>
<span class="text-primary"> {{ data?.shiftGodown?.outletName }} </span>
</span>
</mat-card-content>
</mat-card>
</div>
Ts file
======
get totalProductList() {
let quantity: number;
this.transactionData.stockShift.forEach(stock => {
quantity = stock.productList.reduce((stock, list) => {
return stock + list.quantity;
}, 0)
});
return quantity;
}
1 solution - if you want to use getter totalProductList you can create a component for your box and in this case getter will work as expected.
stock.component.ts for example
get totalProductList() {
return this.stock.productList.reduce((stock, list) => {
return stock + list.quantity;
}, 0)
});
}
2 solution (BAD, cause call function in template) - you need to transform you getter to function and pass one box element to work correctly
ts
getTotalProductList(stock) {
return stock.productList.reduce((stock, list) => {
return stock + list.quantity;
}, 0)
});
}
html
<span class="text-primary">({{getTotalProductList(data)}} Quantities)</span>
3 solution - also transform you getter to function and call it for each element when you receive data and save to element property (stock .quantitiesSum for example, and use in html {{stock .quantitiesSum}})
p.s.
I think you should compare productList.length instead productList[0].quantity here
<span *ngIf="data && data?.productList[0]?.quantity < 1">
to
<span *ngIf="data && data?.productList.length < 2">

How to get my dates out of local storage and set them without the time?

I have an event form that where I get information put it in the localstorage (I cannot use an API) and I want to take the startdate and enddate out of localstorage, change them so they appear as dd-mm-yyyy (not yyyy-mm-ddT00:00:00.000Z) The issue is getting them out of the array and setting them. I have no idea where to begin....
Here is my JavaScript/jQuery:
.controller("Events", function($scope, $location) {
let URL = "https://morning-castle-91468.herokuapp.com/";
$scope.authToken = localStorage.getItem("authToken");
$scope.username = localStorage.getItem("username");
$scope.events = [];
let lastEvent = 0;
while (localStorage.getItem("event"+lastEvent)){
$scope.events.unshift(JSON.parse(localStorage.getItem("event"+lastEvent)));
lastEvent++;
}
JSON.parse(localStorage.getItem("event")) || [];
$scope.submitForm = function() {
if ($scope.eventForm.$valid) {
$scope.event.username = $scope.username;
localStorage.setItem("event"+lastEvent, JSON.stringify($scope.event));
}
};
})
And here is my HTML:
<div class="row eventcontent" ng-repeat="event in events">
<div class="col-xs-12 eventpost">
<div class="row-flex">
<div class="col-xs-8 ">
<h4>{{ event.title }}</h4>
</div>
<div class="col-xs-4 ">
<h4>{{ event.name }}</h4>
</div>
<div class="col-xs-12 ">
<td>{{ event.description }}</td>
<br />
<br />
<p>{{ event.address }} <br /> {{ event.country }}</p>
<br />
<p>{{ event.status }}</p>
</div>
<div class="col-xs-12 ">
<p>{{ event.startdate }} {{ event.enddate }}</p>
</div>
</div>
</div>
</div>
To get Data from localstroage which will be an JSON ArrayList then,
var retrievedData = JSON.parse(localStorage.getItem("event"+lastEvent));
var setDateFormat = $filter('date')(new Date((retrievedData[1].substr(6)), 'dd-mm-yyyy'));
I'm not used to Angular.
But anyway, it looks like you are creating an array events having all the previously stored event.
You use unshift which is adding each event at the beginning of the array. The result probably is like so (for 2 elements):
$scope.events:
[ // That is event1
{
name:someValue,
description:someValue,
address:someValue,
country:someValue,
status:someValue,
startdate:"yyyy-mm-ddT00:00:00.000Z",
enddate:"yyyy-mm-ddT00:00:00.000Z"
},
// That is event0
{
//Same structure as above...
}
]
So now,, assuming you wish to have the last event, which is the first element in the events array, and the structure is as above, I would try:
// Retreive the dates from the first array element... Only the part before the "T" in each string.
var retreived_start = $scope.events[0].startdate.split("T")[0];
var retreived_end = $scope.events[0].enddate.split("T")[0];
// Split the date by the "-" to re-order...
var start_parts = retreived_start.split("-");
var end_parts = retreived_start.split("-");
// YYYY-MM-DD results
var formatted_start = start_parts[2] +"-"+ start_parts[1] +"-"+ start_parts[0];
var formatted_end = end_parts[2] +"-"+ end_parts[1] +"-"+ end_parts[0];
// Place it in your Angular controller array (? -- I'm unsure here)
$scope.event.startdate = formatted_start;
$scope.event.enddate = formatted_end;
But now that you've modified the event array... It may be stored as "formatted"... So be aware of that!
That line is doing absolutely nothing: JSON.parse(localStorage.getItem("event")) || [];, since not assigned to a variable, you can safely remove it.

Change text depending on the size of the array in AngularJS

I have the following scope and if this is greater than 5, I'd like to display something like 'more than ten items' otherwise it will just list the items in a human readable list
<span class="bold-words">{{rule.words.join(', ')}}</span>
What is the correct AngularJS way to do this?
e.g so it would show like below
// less than 5
Your list is "peas, fruit, tea"
// more than 5
Your list is greater than 5 items
You can do it easily with ternary operator
<span class="bold-words">Your list is {{ rule.words.length > 5 ? 'greater than 5 items' : rule.words.join(', ') }}</span>
try something like this ...
<span class="bold-words">Your list is {{(rule.words.length>5)?'greater than 5 item':(rule.words.join(', '))}}</span>
I would prefer a filter like {{ rule.words | beautifier:5 }} So you can use it on different cases and can modify your output at will. See the snippet for a working example:
var app = angular.module('bar', []);
app.controller('foo', function($scope) {
$scope.bar = ['asdasd', 'egeg', 'hjgkj', 'adaa'];
});
app.filter('beautifier', function() {
return function(input, count) {
var output;
if (input.length > count) {
output = 'Your list is greater than ' + count +' items.';
} else {
output = 'Your list is "' + input.join('", "') + '"';
}
return output;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="bar">
<div ng-controller="foo">
<p>{{ bar | beautifier:5 }}</p>
<p>{{ bar | beautifier:3 }}</p>
</div>
</div>

Stop loop using ng-if condition in angularJS

I have this code. $scope.counter = '1';
<div ng-repeat="cat in catadata">
<div ng-if="cat.TopCategoryID = 2" >
<div ng-if="counter = 1" >
<div class="feedsDisplay" ng-init="counter = counter + 1">
Creater Img:{{cat.CreatedBy_Profile.Picture.URI}}"
</div>
</div>
</div>
</div>
I want to stop loop when counter = 2, I want to display just 1 result.
ng-init="counter = counter + 1
{{counter}}
displaying 11111 it should display 12345
you are comparing with = instead of ==
Try like this
ng-if="counter == 1"
value of counter is string . add + sign before counter
try like this
ng-init="counter = +counter + 1"
You cant stop ng-repeat conditionally.
To print only one result you can use
<div ng-repeat="cat in catadata | limitTo : 1">
OR
<div>{{catadata[0]}}</div>
Rather than misusing ng-repeat, ng-init and ng-if like this, just try to extract the first matching cat before you render it, e.g. in a controller, directive or service:
for (var i = 0, maxI = catadata.length; i < maxI; ++i) {
if (cat.TopCategoryID === 2) {
$scope.firstMatchingCat = cat;
break;
}
}
And then in the template:
<div class="feedsDisplay">
Creater Img:{{firstMatchingCat.CreatedBy_Profile.Picture.URI}}"
</div>

angularjs ng-class with different conditions

i have a view which shows data and i want to add another class on the list items in my view.
<input type="text" class="filter" placeholder="search..." ng-model="search">
<ul>
<li ng-repeat="item in items | filter:search | orderBy:'date'">
{{ date }} {{ item.heading }}<button ng-click="deleteItem(item.ID)"><i class='icon-trash'></i></button>
</li>
</ul>
i have a variables called item.date and i want to compare it to another variables today. Here is the logic:
if (item.date - today <= 0)
apply class1
if else (item.date - today > 0 && item.date - today <= 3)
apply class2
and so on
how can i achieve this with angular?
can i put this logic directly into my view or do i need to define it in my controller?
thanks in advance
Since you have a bit heavy comparisons to make, I would suggest moving it inside a function rather than having it in HTML:
<li ng-class="getClass(item.date)"
ng-repeat="item in items | filter:search | orderBy:'date'">
JS:
$scope.getClass = function(date){
/* comparison logic here*/
/* returs class name as string */
}
I think you can use ng-class like this:
HTML
<li ng-class="{'class1': item.date - today <= 0, 'class2': (item.date - today > 0 && item.date - today <= 3)}"></li>
OR moving it inside a function like this:
HTML
<li ng-class="getClass(item.date)"></li>
JS
$scope.getClass = function(date){
return {'class1': item.date - today <= 0, 'class2': (item.date - today > 0 && item.date - today <= 3)};
}

Categories