I want to return the value length of a scope variable who contains an array of objects. Well, my idea was to reduce the html view and to store the variables in my controller. The problem is when I call the value in the console I'm getting always the length 0.
The following code considered the previous view:
<div class="panel panel-default">
<div class="panel-body bg-form">
<div class="col-sm-4">
<strong>total:</strong>
</div>
<div class="col-sm-3">
<span class="badge"> {{ nameslist.length }}</span>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-body bg-form">
<div class="col-sm-4">
<strong>filtered:</strong>
</div>
<div class="col-sm-3">
<span class="badge"> {{ filteredNames.length }}</span>
</div>
</div>
</div>
...
<tr ng-repeat="names in filteredNames = (nameslist | orderBy:sortType:sortReverse)" class="show-cursor">
<td>{{ names.fname }}</td>
<td>{{ names.lname }}</td>
</tr>
These should be the new code:
<div class="panel panel-default" ng-repeat="sResult in searchResult">
<div class="panel-body bg-form">
<div class="col-sm-4">
<strong>{{ sResult.title }}:</strong>
</div>
<div class="col-sm-3">
<span class="badge"> {{ sResult.content }}</span>
</div>
</div>
</div>
Ctrl:
$scope.nameslist = CrudService.getAllNames();
$scope.searchResult = [
{
title: 'total',
content: $scope.nameslist.length
},
{
title: 'filtered',
content: $scope.filteredNames.length
}
];
Service:
myApp.factory('CrudService', ['ResService',
function (ResService) {
return {
getAllNames: function () {
return ResService.names.query();
},
...
}]);
myApp.factory('ResService', ['$resource', 'baseUrl',
function ($resource, baseUrl) {
return {
names: $resource(baseUrl + '/api/names/:Id/:fname', {
Id: '#Id',
fname: '#fname'
}, {
'update': {
method: 'PUT'
}
}),
...
}]);
How can I return only the number of the array and the filtered number of the array?
This line does not immediately populate the object;
$scope.nameslist = CrudService.getAllNames();
From the angular documentation on $resource:
It is important to realize that invoking a $resource object method
immediately returns an empty reference (object or array depending on
isArray). Once the data is returned from the server the existing
reference is populated with the actual data.
You need to bind to the object $scope.namelist in your view, or, wait until the promise is resolved and then assign the properties in the success callback.
One solution is as follows;
Javascript
$scope.searchResult = [{
title: 'total',
content: $scope.nameslist // holds a reference to the item returned by CrudService
}]
View
<div class="col-sm-4">
<strong>{{ searchResult.title }}:</strong>
</div>
<div class="col-sm-3">
<span class="badge"> {{ searchResult.content.length }}</span>
</div>
Related
I'm new to Angular and I can't really understand what is the problem I'm facing. I'm trying to pass object from an *ngFor to his component.
Here is a simple *ngFor that iterate an Array
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor }}</span>
</span>
</div>
</div>
I want to avoid this long interpolation so I want pass the current let alarm to the component and assign three attributes to an object and display it,
customMethod(alarm) {
this.location.floor = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor;
this.location.room = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].room;
this.location.bed = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].bed;
}
Here is what I expect:
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ location.floor }}</span>
</span>
</div>
</div>
And show the attribute's object location with string interpolation for each object alarm.
What is the best way to do this?
You want to avoid having any logic in your template (.html) file so I'll advise doing the logic in your component file.
You can prepare the alarms array before it's sent into the template.
#Component(..)
export class SomeComponent {
private _alarms;
#Input()
set alarms(alarms) {
this._alarms = alarms.map(alarm => customMethod(alarm))
}
get alarms() {
return this._alarms
}
}
function customMethod(alarm) {
return {
...alarm, // <<< remove this if you just want locations
locations: {
floor: alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor,
room: ....,
bed: ...
}
}
Then in your template
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ alarm.location.floor }}</span>
</span>
</div>
</div>
Create a helper method to get you the value you want to display, and then just call that from the template.
You can do anything to the object to get the value you want to display in here since it's just a funciton:
createMyString(alarm) {
return alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor;
}
Then in your template
{{createMyString(alarm)}}
I want to print out the value in my array, not the ['value']. It should create a div='col-md' box for each index in the array.
const app = new Vue({
el: "#app",
data() {
return {
step: 1,
ansPurchaseonly: [
['Leasehold', 'Freehold'],
['Leasehold', 'Freehold']
],
HTML template:
<div class="row white-boxes justify-content-center">
<div class="col-md-3 col-sm-12 h-100 d-table" v-for="(opt, index) in ansPurchaseonly">
<span>{{ opt }}</span>
</div>
</div>
</div>
Instead I get an output like [ "Leasehold", "Freehold" ] in the html rendered page. I want just:
Leasehold
Freehold
Seems you need to run another loop
<div class="col-md-3 col-sm-12 h-100 d-table" v-for="opt in ansPurchaseonly">
<div v-for="elem in opt">
<span>{{ elem }}</span>
</div>
</div>
You can use another v-for, because your "opt" is still an array or alternatively you can use join the values like
<div class="row white-boxes justify-content-center">
<div class="col-md-3 col-sm-12 h-100 d-table"
v-for="(opt, index) in ansPurchaseonly">
<span>{{ opt.join(' ') }}</span>
</div>
</div>
How can I use ng-repeat to loop over data that contains many nested array data?
I have data that will have many "Segments"
Example:
confirm.booking.flightData[0].Segments[0].FlightNumber
confirm.booking.flightData[0].Segments[1].FlightNumber
confirm.booking.flightData[0].Segments[2].FlightNumber
I have done both ng-repeat with angular, and without angular I would end up resorting to javascript that loops over data and creates the html dynamically, but I wish to do this the ANGULAR way.. HOW?
HTML with Angular/Javascript Arrays:
<div class="container-fluid">
<div class="row">
<div class="col-md-4">
<span style="font-weight: bold;">Flight</span>
</div>
<div class="col-md-4">
<span style="font-weight: bold;">Departs</span>
</div>
<div class="col-md-4">
<span style="font-weight: bold;">Arrives</span>
</div>
</div>
<div class="row">
<div class="col-md-4">
{{confirm.booking.flightData[0].Segments[0].FlightNumber}}
</div>
<div class="col-md-4">
({{confirm.booking.flightData[0].Segments[0].DepartureAirport}})
</div>
<div class="col-md-4">
({{confirm.booking.flightData[0].Segments[0].ArrivalAirport}})
</div>
</div>
</div>
Nesting can be done in repeats, but repeating too much in ng-repeats can be costly in terms of performance as angular creates scopes for each element repeated. Hence, filtering data till the perfect abstracted values that you need in terms of html should be done in the js file.
For eg: if u need only segements in the html form do this, or if u need even flight data in html form follow #Rachel's post
<ul data-ng-repeat="item in confirm.booking.flightData[0].Segments">
<li>{{ item.FlightNumber}}</li>
</ul>
Let's say your data is in flightdetails, then you can go about it like this:
<div ng-repeat="a in flightdetails ">
<div ng-repeat="b in a.booking">
<div ng-repeat="c in b.flightdata">
<div ng-repeat="d in c.segments">
{{d.flightnumber}}
</div>
</div>
</div>
</div>
You can use nested ng-repeat to bind your data - see a demo below:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.confirm = {
booking: {
flightData: [{
Segments: [{
FlightNumber: 1
}, {
FlightNumber: 2
}]
}, {
Segments: [{
FlightNumber: 3
}, {
FlightNumber: 4
}]
}]
}
}
// console.log($scope.confirm);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="wrapper" ng-app="app" ng-controller="ctrl">
<div ng-repeat="x in confirm.booking.flightData">
Data {{$index + 1}}:
<div ng-repeat="y in x.Segments">
<div>Flight No: {{y.FlightNumber}}</div>
</div>
<br/>
</div>
</div>
If you want to display only the following:
confirm.booking.flightData[0].Segments[0].FlightNumber
confirm.booking.flightData[0].Segments[1].FlightNumber
confirm.booking.flightData[0].Segments[2].FlightNumber
then you can use limitTo - see demo below:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.confirm = {
booking: {
flightData: [{
Segments: [{
FlightNumber: 1
}, {
FlightNumber: 2
}]
}, {
Segments: [{
FlightNumber: 3
}, {
FlightNumber: 4
}]
}]
}
}
// console.log($scope.confirm);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="wrapper" ng-app="app" ng-controller="ctrl">
<div ng-repeat="x in confirm.booking.flightData | limitTo : 1">
Data {{$index + 1}}:
<div ng-repeat="y in x.Segments">
<div>Flight No: {{y.FlightNumber}}</div>
</div>
<br/>
</div>
</div>
I created an example here:
http://codepen.io/ackzell/pen/ENBymo
It ultimately looks like this, but check the pen as it has some more info:
<ul>
<li ng-repeat="flight in vm.flightData">
<ul>
<li ng-repeat="segment in flight.Segments">
<em>FlightNumber</em> {{ segment.FlightNumber }}
<br />
<em>Departure:</em> {{ segment.DepartureAirport }}
<br />
<em>Arrival:</em> {{ segment.ArrivalAirport }}
</li>
</ul>
</li>
</ul>
Nesting ng-repeats would help, but maybe you want to give your data some treatment first.
I have a json file like
{
"Asian_Cities_Countries":[
{"name":"Beijing",
"country":"China"
},
{"name":"Ankara",
"country":"Turkey"
}
],
"European_Cities_Countries":[
{"name":"Paris",
"country":"France"
},
{"name":"Madrid",
"country":"Spain"
}
]
}
It is just a part of a json file the actual json is quite big.
I am fetching this json through angularjs and displaying it my html page as
<div class="panel-group" id="accordion">
<div ng-repeat="key in notSorted(items) track by $index" class="panel panel-default menu-panel" ng-init="value = items[key]" style="margin-bottom:10px;">
<a data-toggle="collapse" data-parent="#accordion" id="menu-link" href="#{{key}}">
<div class="panel-heading panel-types">
<h4 class="panel-title">
{{key}}
</h4>
</div></a>
<div id="{{key}}" class="panel-collapse collapsing menu-items">
<div ng-repeat="item in value">
<div class="row">
<div class="col-sm-12 col-lg-3">
<p class="item-name">
{{item.name}}
</p>
</div>
<div class="col-sm-12 col-lg-3">
<p>{{item.country}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
Now I want to remove underscores from the key value and replace it with blank spaces.How do i do it.
I tried {{key.replace('_',' ')}} . But it removes only the first underscore and not all of them.
var app = angular.module("app",[]);
app.controller("ctrl" , function($scope){
$scope.items = {
"Asian_Cities_Countries":
[
{"name":"Beijing","country":"China"},
{"name":"Ankara","country":"Turkey"}
],
"European_Cities_Countries":
[
{"name":"Paris","country":"France"},
{"name":"Madrid","country":"Spain"}
]
};
});
app.filter('removeUnderscores', [function() {
return function(string) {
if (!angular.isString(string)) {
return string;
}
return string.replace(/[/_/]/g, ' ');
};
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl" class="panel-group" id="accordion">
<div ng-repeat="(key,value) in items track by $index" class="panel panel-default menu-panel" ng-init="value = items[key]" style="margin-bottom:10px;">
<a data-toggle="collapse" data-parent="#accordion" id="menu-link" href="#{{key}}">
<div class="panel-heading panel-types">
<h4 class="panel-title">
{{key | removeUnderscores}}
</h4>
</div></a>
<div id="{{key}}" class="panel-collapse collapsing menu-items">
<div ng-repeat="item in value">
<div class="row">
<div class="col-sm-12 col-lg-3">
<p class="item-name">
{{item.name}}
</p>
</div>
<div class="col-sm-12 col-lg-3">
<p>{{item.country}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
try this. use a filter similar this
app.filter('removeUnderscores', [function() {
return function(string) {
if (!angular.isString(string)) {
return string;
}
return string.replace(/[/_/]/g, ' ');
};
}])
and in html
{{key | removeUnderscores}}
Seems you forgot the global modifier, try this:
key.replace(/_/g,' ')
with "g" all occurences should be replaced
The AngularJS Docs specifically state that Angular Expressions don't include regular expressions.
Angular Expressions vs. JavaScript Expressions
Angular expressions are like JavaScript expressions with the following differences:
No RegExp Creation With Literal Notation: You cannot create regular expressions in an Angular expression.
-- AngularJS Developer Guide - Expressions
Instead use a custom filter as recommended by #hadijz
app.filter('removeUnderscores', [function() {
return function(string) {
if (!angular.isString(string)) {
return string;
}
return string.replace(/[/_/]/g, ' ');
};
}])
and in html
{{key | removeUnderscores}}
Just a question. Why aren't you processing the json file/data within a service? This much processing (especially string replacing) isn't meant to be done in either the HTML or the controller in AngularJS.
I'd recommend that you parse the json inside a service and then pass it to the controller. That's usually the best practice..
Please see this JSBIN for reference. Thank you
So I have these boxes that show minimal info for an array created using an ng-repeat. There could be 1 and 10 items returned with objects and their properties These boxes are clickable and when clicked, should populate the table. Problem is, I keep getting a reference error and for the likes of me, cannot see why. The function is defined and should call and fill the table based on the Id of the box to fill the table with more info. The array object is called "swipe".
My html for the the boxes:
<div class="swipeBoxes" ng-repeat="swipe in swipes">
<a href="" ng-click="editSwipe(swipe.id)" >
<div class="swipeBox col-md-12">
<div class="col-md-12 claimObject">
<span class="claimLine" style="width: 3px; position: absolute; top: 5px; left: 5px;">{{ $index + 1 }}.</span>
<span class="claimedLeft">swipe date:</span>
<span class="claimedRight">{{ swipe.date | date: 'MM/dd/yyyy'}}</span>
</div>
<div class="col-md-12 claimObject">
<span class="claimedLeft">provider:</span
><span class="claimedRight">{{ swipe.merchant }}</span>
</div>
<div class="col-md-12 claimObject">
<span class="claimedLeft">amount:</span>
<span class="claimedRight">{{ swipe.amount | currency }}</span>
</div>
</div>
</a>
</div>
My target table that should be filled with data once one of the objects are selected from above:
<div class="swipeDetails col-md-12">
<div class="swipeFlexHead col-md-12">
<p>Swipe Details</p>
</div>
<div class="swipeFlexHead2 col-md-12">
<p>{{ swipe.merchant }}</p>
</div>
<div class="col-md-12">
<div class="swipeFlexElement col-md-4">
<p>Swipe Date</p>
<p>{{ swipe.date | date: 'MM/dd/yyyy' }}</p>
</div>
<div class="swipeFlexElement col-md-4">
<p>Status</p>
<p>{{ swipe.status }}</p>
</div>
<div class="swipeFlexElement col-md-4">
<p>Card Used</p>
<p>{{ swipe.cardHolder }} {{ swipe.cardUsed }}</p>
</div>
</div>
<div class="col-md-12">
<div class="swipeFlexElement col-md-4">
<p>Swipe Amount</p>
<p>{{ swipe.amount | currency }}</p>
</div>
<div class="swipeFlexElement col-md-4">
<p>Amount Requiring Documentation</p>
<p>{{ swipe.reqAmount | currency }}</p>
</div>
<div class="swipeFlexElement col-md-4">
<p>Documentation Due Date</p>
<p>{{ swipe.dueDate | date: 'MM/dd/yyyy' }}</p>
</div>
</div>
</div>
And finally, my controller for this that is pulling data and has the 'editSwipe' function:
app.controller('swipeController', ['$scope', 'swipesService', '$location', 'Upload', '$timeout', '$filter', 'utilsService',
function ($scope, swipesService, $location, Upload, $timeout, $filter, utilsService) {
$scope.swipes = [];
$scope.swipeFormSubmitted = false;
swipesService.getSwipes().then(function (results) {
$scope.swipes = results.data;
});
$scope.swipe = {
id: '',
descr: '',
merchant: '',
date: '',
amount: '',
reqAmount: '',
status: '',
cardUsed: '',
cardHolder: '',
dueDate: ''
}
$scope.editSwipe = function(id) {
$scope.swipeInfo = angular.copy(swipe);
};
}]);
In your editSwipe function you are not doing anything with id. With angular.copy(swipe) you are using swipe which is not defined. I guess you want to copy the swipe you've clicked, then you need to do
ng-click="editSwipe(swipe)"
$scope.editSwipe = function(swipe) {
$scope.swipe = angular.copy(swipe); // I don't see where you use swipeInfo?
};
BTW: is there any need to deep copy the swipe? Can't you just pass the reference $scope.swipe = swipe;