I wanted to know if I can split a string simply in angularJS.
I have my
$scope.test = "test1,test2";
in my controller and in my view,
I wanted to do something like that
{{test[0] | split(',')}}
{{test[1] | split(',')}}
I've seen a lot thing about input and ng-change calling a function in the controller that split the string or something with ng-list but nothing works in my case.
thx to all.
You may want to wrap that functionality up into a filter, this way you don't have to put the mySplit function in all of your controllers. For example
angular.module('myModule', [])
.filter('split', function() {
return function(input, splitChar, splitIndex) {
// do some bounds checking here to ensure it has that index
return input.split(splitChar)[splitIndex];
}
});
From here, you can use a filter as you originally intended
{{test | split:',':0}}
{{test | split:',':0}}
More info at http://docs.angularjs.org/guide/filter (thanks ross)
Plunkr # http://plnkr.co/edit/NA4UeL
Thx guys, I finally found the solution, a really basic one..
In my controller I have
$scope.mySplit = function(string, nb) {
var array = string.split(',');
return array[nb];
}
and in my view
{{mySplit(string,0)}}
You can try something like this:
$scope.test = "test1,test2";
{{test.split(',')[0]}}
now you will get "test1" while you try {{test.split(',')[0]}}
and you will get "test2" while you try {{test.split(',')[1]}}
here is my plnkr:
http://plnkr.co/edit/jaXOrZX9UO9kmdRMImdN?p=preview
You could try this:
$scope.testdata = [{ 'name': 'name,id' }, {'name':'someName,someId'}]
$scope.array= [];
angular.forEach($scope.testdata, function (value, key) {
$scope.array.push({ 'name': value.name.split(',')[0], 'id': value.name.split(',')[1] });
});
console.log($scope.array)
This way you can save the data for later use and acces it by using an ng-repeat like this:
<div ng-repeat="item in array">{{item.name}}{{item.id}}</div>
I hope this helped someone,
Plunker link: here
All credits go to #jwpfox and #Mohideen ibn Mohammed from the answer above.
The Easiest one for AngularJS
{{test.split('T')[0]}}
Related
I'm working on a data heavy Angular project in which I have a ng-repeat where many values get updated every second. If a value is empty, it now updates the DOM to show an empty value; which is correct behaviour.
Needed solution
What I want is a filter or expression which doesn't update the value in the DOM when the new value is empty or NULL. Latching data, I believe they call it.
Possible solutions
I found a couple of possible solutions with $watch, but I believe they are not suitable in ng-repeat, or at least not efficient:
angularjs $watch old value and new value are the same
Example of what I would like to achieve: (this does not work)
app.filter('latchIt', function () {
return function (valueOld, valueNew) {
if (valueNew == '') {
// Do not update the DOM for this value, perhaps a return of the old value
return valueOld;
} else {
return valueNew;
}
};
});
HTML
<div class="item" ng-repeat="item in items track by item.id">
<div class="value" ng-repeat="value in item.data">{{ value | latchIt }}</div>
</div>
Thanks in advance for any help & advice you can give me.
I'd create a directive for that:
codepen: http://codepen.io/anon/pen/EVXgjz
angular.module('app').directive('latched', [function() {
return {
template: '<span>{{saved}}</span>',
link: function($scope) {
$scope.$watch('value', function(val) {
if (!$scope.saved) {
$scope.saved = val || 'Not defined yet';
}
if (val) {
$scope.saved = val;
}
})
},
scope: {
value: '='
}
}
}])
Well I would say that $watch option is good enough to use it, but if you are agains it you can try to combine old collection values and new collection values according to your business rules in controller/directive and after than pass it to view.
I have a dropdown with values in it. They're accessed through the .value property. I have an ng-repeat on a div that is repeating a lot of data. That data has statuses. When a user selects to filter by a status in the dropdown, I want to filter the ng-repeat by whatever status they chose and the status in the ng-repeat. Here's a better example of what I mean:
data-ng-repeat="stackoverflow in overflows| filter:stackoverflow.property.status===status.value"
In my case, I need to access stackoverflow.property.status and compare it to whatever status is in the drop down.
You'll want to do something like the following:
<span ng-repeat="stackoverflow in overflows | filter: { status : selectedStatus }"></span>
selectedStatus will be the value of ng-model on your dropdown.
You could have something like this
ng-repeat="stackoverflow in overflows | filter: { locations: [{ status: status.value }] }"
Under the circumstances, it ended up just being easier to write my own function and filter by it. In this case, I have a function search that I pass to filter. Works great for me.
I followed an answer that I found on another question. You can view it here: http://jsfiddle.net/suCWn/
$scope.search = function (shop) {
if ($scope.selectedCityId === undefined || $scope.selectedCityId.length === 0) {
return true;
}
var found = false;
angular.forEach(shop.locations, function (location) {
if (location.city_id === parseInt($scope.selectedCityId)) {
found = true;
}
});
return found;
};`
Here's the question: Angularjs filter nested object
It's possible to make for exmple :
<p>{{data.country}}</p> print out Country:New York, how to alter that to Country:NY ?
You could do it using Regx .match and strings join method.
Markup
{{data.country.match(pattern).join('')}}
Controller
app.controller('MainCtrl', function($scope, $http) {
$scope.data = {};
$scope.data.country = 'New York';
$scope.pattern = /\b(\w)/g;
});
Demo Plunkr
Create a custom filter:
.filter("countryCaps", function(){
return function(country){
return "Country: " + country.match(/[A-Z]/g).join("")
}
})
<p>{{data.country | countryCaps}}</p>
Demo
Always remember that what you have inside the {{...}} is an AngularJS expression. That means you can call functions as well.
Just put a function on your scope like this:
$scope.countryTranslator = function (country) {
if (country === 'New York') {
return 'NY';
}
};
and call it like this instead:
{{ countryTranslator(data.country) }}.
Obviously your "translator" should have better code than my example, but you get the idea.
You should use custom filter for this purpose.
But you still have a problem with database of cities full name and they shortcuts, for this purpose, you can use static json file, or use side server service in your choice.
I'm using a UI.Bootstrap accordion and I've defined my heading like so:
<accordion-group ng=repeat="(cname, stations) in byClient">
<accordion-heading>
{{ cname }} <span class="pull-right"> {{ Object.keys(stations).length }} Stations</span>
</accordion-heading>
When that displays the Object.keys(stations).length resolves to nothing. If I put that same length call in my controller I get back the expected count. Is there something preventing the method call from working in AngularJS?
The rest of the accordion that uses stations acts as expected, so I know that it's being populated properly. The byClient data structure basically looks like so:
{
"Client Name" : {
"Station Name": [
{...},
{...}
]
}
}
Yes, That is because Object is a part of window/global and angular cannot evaluate that expression against the scope. When you specify Object.keys in your binding angular tries to evaluate it against the $scope and it does not find it. You could store the reference of object.keys in some utility in rootScope and use it anywhere in the app.
Something like this:-
angular.module('yourApp',[deps...]).run(function($rootScope){
//Just add a reference to some utility methods in rootscope.
$rootScope.Utils = {
keys : Object.keys
}
//If you want utility method to be accessed in the isolated Scope
//then you would add the method directly to the prototype of rootScope
//constructor as shown below in a rough implementation.
//$rootScope.constructor.prototype.getKeys = Object.keys;
});
and use this as:-
<span class="pull-right"> {{ Utils.keys(stations).length }} Stations</span>
Well this will be available to any child scopes except for isolated scopes. If you are planning to do it on the isolated scope (eg:- Isolated scoped directives) you would need to add the reference of Object.keys on the scope, or as you expose a method on the scope which will return the length.
Or better yet , create a format filter to return the keylength and use it everywhere.
app.filter('keylength', function(){
return function(input){
if(!angular.isObject(input)){
throw Error("Usage of non-objects with keylength filter!!")
}
return Object.keys(input).length;
}
});
and do:-
{{ stations | keylength }}
Demo
Use the function to determine the number of object properties:
$scope.keyLength = function (obj) {
return Object.keys(obj).length;
}
and use:
{{ keyLength(myObj) }}
I think filters are the most AngularJS way of handling structures in template code:
angular.module('app.filters').filter('objectKeysLength', [function() {
return function(items) {
return Object.keys(items).length;
};
}]);
angular.module('app.filters').filter('objectKeys', [function() {
return function(item) {
if (!item) return null;
var keys = Object.keys(item);
keys.sort();
return keys;
};
}]);
In case someone searches for angular 2 and higher solution. It now hat keyvalue pipe, which can be used to interate over objects
I could not get any of the other answers to work in AngularJS 1.6. What worked for me
using $window to acccess Object.keys like this $window.Object.keys({ 'a': 1, 'b': 2 })
Here's a solution that worked for me :
export class xyzcomponent{
Key = Object.keys;
}
Now in the component html file, you can use something like that :
<li *ngFor="let i of Key(stations)">.........</li>
What I'm trying to do:
I am trying to dynamically update a scope with AngularJS in a directive, based on the ngModel.
A little back story:
I noticed Angular is treating my ngModel strings as a string instead of an object. So if I have this:
ng-model="formdata.reports.first_name"
If I try to pull the ngModel in a directive, and assign something to it, I end up with $scope["formdata.reports.first_name"]. It treats it as a string instead of a nested object.
What I am doing now:
I figured the only way to get this to work would be to split the ngModel string into an array, so I am now working with:
models = ["formdata", "reports", "first_name"];
This works pretty good, and I am able to use dynamic values on a static length now, like this:
$scope[models[0]][models[1]][models[2]] = "Bob";
The question:
How do I make the length of the dynamic scope dynamic? I want this to be scalable for 100 nested objects if needed, or even just 1.
UPDATE:
I was able to make this semi-dynamic using if statements, but how would I use a for loop so I didn't have a "max"?
if (models[0]) {
if (models[1]) {
if (models[2]) {
if (models[3]) {
$scope[models[0]][models[1]][models[2]][models[3]] = "Bob";
} else {
$scope[models[0]][models[1]][models[2]] = "Bob";
}
} else {
$scope[models[0]][models[1]] = "Bob";
}
} else {
$scope[models[0]] = "Bob";
}
}
This is an answer to
I noticed Angular is treating my ngModel strings as a string instead of an object
Add the require property to your directive then add a fourth ctrl argument to your link function
app.directive('myDirective', function() {
return {
require: 'ngModel',
link: function(scope, element, attributes, ctrl) {
// Now you have access to ngModelController for whatever you passed in with the ng-model="" attribute
ctrl.$setViewValue('x');
}
};
});
Demonstration: http://plnkr.co/edit/Fcl4cUXpdE5w6fHMGUgC
Dynamic pathing:
var obj = $scope;
for (var i = 0; i<models.length-1; i++) {
obj = obj[models[i]];
}
obj[models[models.length-1]] = 'Bob';
Obviously no checks are made, so if the path is wrong it will fail with an error. I find your original problem with angular suspicious, perhaps you could explore a bit in that direction before you resort to this workaround.