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
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'm new to front-end web development. I am creating checkboxes dynamically using AngularJS.
<div ng-repeat="x in Brands" style="margin-left: 20px">
<input type="checkbox" ng-model="newObject[x.product_brand]">
<label> {{ x.product_brand }} </label>
</div>
Following the methods given on the links below, I want to hide/show divs using
using the dynamically created checkboxes.
Dynamic ng-model
ng-show
Here's the code-
<div class="item panel panel-default" ng-repeat="x in Brands" ng-show="newObject[x.product_brand]">
<div class="panel-heading">
{{x.product_brand}}
</div>
<div class="panel-body">
</div>
</div>
Controller-
app.controller('BrandController', function($scope, $http) {
getProductsInfo();
function getProductsInfo() {
$http.get("sql.php").success(function(data) {
$scope.Brands = data;
});
};
});
But it is not working. Checking/Unchecking the checkboxes does nothing.
I think you need something like this runnable fiddle. This kind of handle is easy to manage with AngularJS. Welcome =) !!! Please note: The $timeout is to simulate your async $http request - its not a part of the solution.
View
<div ng-controller="MyCtrl">
<div ng-repeat="x in Brands" style="margin-left: 20px">
<input type="checkbox" ng-model="x.active">
<label> {{ x.product_brand }} </label>
</div>
<div class="item panel panel-default" ng-repeat="x in Brands" ng-show="x.active">
<div class="panel-heading">
{{x.product_brand}}
</div>
<div class="panel-body">
</div>
</div>
</div>
AngularJS demo application
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope, $timeout) {
$scope.Brands = [];
init();
function init () {
$timeout(function () {
$scope.Brands = [{
product_brand: 'brand 1'
},{
product_brand: 'brand 2'
},{
product_brand: 'brand 3'
},{
product_brand: 'brand 4'
}];
});
}
});
Probably it is not working because you never defined newObject on the $scope. So actually you are trying to access undefined[x.product_brand].
Something like $scope.newObject = {}; in your Controller should do the trick.
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 am trying to use directive in mu page ..I am trying to send data from controller to directive .I am trying to display data using ng-repeat.
here is I am applying the ng-repeat .
<div class="container">
<!--Row with two equal columns-->
<div class="row " ng-repeat='d in data'>
<div class="col-sm-3">
<div class="demo-content">{{d.Location}}</div>
</div>
<div class="col-md-7">
<div class="demo-content bg-alt description-ellipse">{{d.description}}</div>
</div>
<div class="col-md-1">
<div class="demo-content bg-alt">
<button type="button" class="btn btn-default view-now-button">VIEW NOW</button>
</div>
</div>
</div>
</div>
I make a directive like this
.directive('listComponent', function() {
return {
restrict: 'E',
scope: {
data:'='
},
templateUrl: 'list.html',
link: function(s, e, a) {
}
}
})
I am sending data like that
data:'=' and from here <list-component data='h.data'></list-component>
here is my code
http://plnkr.co/edit/Q0GQC2Pik7m25HxQIW8H?p=preview
It should be:
<div class="row " ng-repeat='d in data.jobs'>
in list.html
Or, as per comment:
<list-component data='h.data.jobs'></list-component>
Updated Plunker
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>