alter string within angularjs expression - javascript

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.

Related

angularjs directive to manipulate text values

I want to create angular directives to change or format binded text values.
My values are like this: var priceList = [12.90, 15.90, 80, 55.90];
I want to use a directive and write priceList values as currency format.
<li ng-repeat"price in priceList">
<span currency>{{price}}</span>
</li>
and directive
angular
.module("app.financal")
.directive("currency", [function () {
return {
restrict: "A",
link: function (scope, element, attribute) {
// if currency vale is not null.
var curr = element.html() + "$";
element.html(curr);
}
}
}]);
how can I get <span currency>{{price}}</span> element price value and change in directive.
More simple than a directive, you can use the currency filter to format your data with currency. It already exists in Angular. Filters are used to format displayed data in Angular.
<li ng-repeat"price in priceList">
<span>{{price | currency}}</span>
</li>
See the docs for more details (you can add a symbol if you want).
It may be that you're looking to write your own custom filters, so here's some literature on how to do that:
https://docs.angularjs.org/guide/filter
Consider the following code:
.filter('customCurrency', function() {
return function ( input ) {
// if currency value is not null.
var out = input + '$';
return out;
};
})
This will do what you have outlined above if you change your html to read:
<li ng-repeat="price in priceList">
<span>{{price | customCurrency}}</span>
</li>
#e666's answer will get you to the desired end result. If you're looking to do the work inside the directive you're going to have to access the bound value of the variable directly.
Before we crack into that, I just want to point out that there are two barriers inside the code as written that we should address before moving on. The first is that var priceList = [ 12.90, 15.90, 80, 55.90 ]; isn't currently on $scope. We can fix this by defining it as $scope.priceList = [ 12.90, 15.90, 80, 55.90 ];.
Next, you'll need to ensure that your ng-repeat is assigned a value. ng-repeat"price in priceList" should therefore be rewritten as an assignment of ng-repeat="price in priceList". You'll then have access to scope.price inside the directive. Sorry for the fussy little details, but they needed to be addressed in order to get price into your directive's scope.
As for the directive, as it sits currently, element.html() will return a value of {{price}}, so that's not what we want. Since scope.price is bound data, we can now modify it directly inside the directive to achieve the desired result.
So your HTML will be slightly modified as outlined above:
<li ng-repeat="price in priceList">
<span currency>{{price}}</span>
</li>
and your directive will be:
angular
.module("app.financal")
.directive("currency", [function () {
return {
restrict: "A",
link: function (scope, element, attribute) {
// if currency vale is not null.
scope.price = scope.price + "$";
}
}
}]);
Please keep in mind that this is going to return a list with the "$" appended to the end of the string, so the output will be:
12.9$
15.9$
80$
55.9$
Lastly, here's a little (tangentially) related reading for you:
Using Filters With Directives in AngularJS

passing object value to directive instead of any other data variable

I am trying to customize this working http://jsfiddle.net/markcoleman/JNqqU/ ,in current working fiddle directly object is assigned . where i am trying to change it to $scope.obj.items . passing object to directive is not working .
do i need to write some $watch fo r the variable ??? i am getting dynamic value that's why i am trying to pass Object value with this .
Code ::
<a href="#" pop-over items="obj.items", title="Mode of transport">
Show Pop over</a>
javascript Directive part ::
scope: {
items: '=',
title: '#'
}
Any suggestion ,
I am trying Below Fiddle
http://jsfiddle.net/JNqqU/652/
You can change your controller to this:
bootstrap.controller('maincnt', function ($scope) {
$scope.obj = { // declare the scope object here with a blank items
items: []
};
$scope.updateitem = function () {
alert('scope update called');
$scope.obj.items = ['car', 'truck', 'plane', 'bike']; // now update here
}
});
Checkout fiddle.
Yes you should be making a watcher.
$scope.$watchCollection('items', function (newValue, oldValue) {
if (newValue) {
buildTemplate(newValue);
}
});
Note: I used watchCollection because it is an array. If it were an object or simple value $watch would be used instead.
You don't need to wrap it into object, but don't 'rewrite' whole array in 'update' method, but push values into it:
bootstrap.controller('maincnt',function($scope){
$scope.items = [];
$scope.updateitem=function(){
alert('scope update called');
$scope.items.push('car', 'truck', 'plane', 'bike');
}
});
http://jsfiddle.net/btfu30k2/1/
$watch isn't necessary too.
You need two changes:
Change in HTML items :: {{obj.items}}
Change in Controller default obj items should be assigned with empty array ( $scope.obj={items:[]}; ) as popOver's $compile is looking for scope.items
See this Working fiddle
Also your testing code {{items | json }} in template can be removed after your observation.

Unable to call Object.keys in angularjs

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>

Converting an array to a nested object

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.

How to split a string with angularJS

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]}}

Categories