Directive to format text to be displayed - javascript

I am playing with AngularJS directive. I want to format the data which is going to be displayed. This is what I am doing:
HTML:
<div ng-app="myApp" ng-controller="myCtrl">
<input ng-model="data" type="text" test />
<input type="button" ng-click="change()" value="Change"> {{data}}
<br>Hello <span ng-bind="data" test></span>
</div>
JS:
angular.module('myApp', [])
.controller('myCtrl', function($scope) {
$scope.data = 'yellow';
$scope.change = function() {
$scope.data = 'black';
};
})
.directive('test', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
ngModel.$formatters.push(function(value) {
//formats the value for display when ng-model is changed
return 'brown';
});
ngModel.$parsers.push(function(value) {
//formats the value for ng-model when input value is changed
return 'green';
});
}
};
});
I am able to format the data for the model and display it for input text. But I am not able to format the data for the span which is bound to a model. span is showing the model as it is. I don't know why the span is showing the value of the model. I want to show the formatted value to the span as well. Here is the jsFiddle.

You can use ng-model for only input. If you want to change a text in a div,span,label or any other element without input you can use seperators . {}
When you create a variable in $scope you can show it in your html.
<div ng-app="myApp" ng-controller="myCtrl">
<input ng-model="data" type="text" test />
<input type="button" ng-click="change()" value="Change"> {{data}}
<br>Hello <span test>{data}</span>
</div>
Fiddle

I think it is working perfectly fine only thing is you are not taking the right example here.
First of all please read below:
Formatters change how model values will appear in the view.
Parsers change how view values will be saved in the model.
and now replace the code below
ngModel.$formatters.push(function(value) {
//formats the value for display when ng-model is changed
return 'brown';
});
ngModel.$parsers.push(function(value) {
//formats the value for ng-model when input value is changed
return 'green';
});
with
ngModel.$formatters.push(function(value) {
//formats the value for display when ng-model is changed
return value.toLowerCase();
});
ngModel.$parsers.push(function(value) {
//formats the value for ng-model when input value is changed
return value.toUpperCase();
});
I hope this help!!

Related

custom filter for hiding the negative values

I have a text box, I want to show nothing in the text box if the ng-model contains negative value, and I want to leave ng-model as it is. And it should not display the data if the data is negative value,If the value is negative then I want to show the empty in text box, but the ng-model should contain that negative value. I need a custom filter to achieve this functionality
Plunker
<input type = "text" ng-model="number"></input>
Filters can be added in AngularJS to format data.
Now, if you are thinking to 'bind' ngModel with the text-box and want to apply filter on it (i.e. markup: <input ng-model="number | nonNegative" />), try-it yourself, you'll get the below error, when you check it in fiddle
Error: Non-assignable model expression: number | nonNegative ()
When you want to show the values are below, using filter, you'll be able to do so.
angular.module('myApp', [])
.controller('LoginController', function ($scope) {
$scope.number = -10;
$scope.number1 = -20;
$scope.number2 = 30;
})
.filter('nonNegative', function(){
return function(val){
if(val >= 0) return val; else '';
}
})
HTML:
Number: {{number | nonNegative}}
<br/>
Number1: {{number1 | nonNegative}}
<br/>
Number2: {{number2 | nonNegative}}
----EDIT-----
Even when you use $watch, the actual value will be different and the value in the textbox will be different.
Check this fiddle
angular.module('myApp', [])
.controller('LoginController', function ($scope) {
$scope.number1 = -20;
$scope.$watch('number1', function(newVal, oldVal) {
if(newVal < 0) newVal = '';
})
})
HTML
<div ng-app="myApp" ng-controller="LoginController">
<input type = "text" ng-model="number1" />
<input type="submit" ng-click="login()" value="Login" />
<br/>
Number1: {{number1 | nonNegative}}
</div>
The number field is having no value, as you see in the fiddle, but still the textbox displays negative value

Refresh element of custom attribute directive in Angular

I have a custom angular directive that I'm using to change the display of price on an item. It's stored as a yearly value and I need to toggle between allowing users to see/edit as yearly or as monthly. So my custom directive is working on my input boxes (not able to use it for a label, div, span, but that's another issue).
I'm able to see that when I toggle the attribute, it picks up the change, but the value in the input doesn't change and I assume it's because not re-rendering the element. Is there any way I can force that to happen?
Here's my directive
angular.module('common.directive').directive('priceMonthly', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ngModel) {
var perMonth = false;
attr.$observe('priceMonthly', function(isMonthly) {
perMonth = (isMonthly.toLowerCase() === "true");
console.log("per month is " + perMonth); //updating perMonth correctly at this point
//guessing I need to do something here or in the function that changes the value of the attribute
});
function fromView(value){
return perMonth ? value * 12 : value;
}
function toView(value){
return perMonth ? value / 12 : value;
}
ngModel.$parsers.push(fromView);
ngModel.$formatters.push(toView);
}
};
});
Here's where I'm using it.
<input type="text" price-monthly="{{monthlySqftView}}"
class="form-control no-animate" name="item.priceLow"
ng-model="item.priceLow" ui-money-mask="2"/>
Here's a jsfiddle of where I'm currently at. So if the dropdown is on monthly, and I type in say 12, the price is correctly 144 which would be the full year price. Now if you change the dropdown to yearly, I need the input to update to 144.
https://jsfiddle.net/6tnbonzy/
Try scope.$apply() after you made required changes
#rschlachter, i am not sure if this can help you. AngularJS uses scope.digest() to clean the dirty data. you might need to put this line of code into your method
attr.$observe('priceMonthly', function(isMonthly) {
perMonth = (isMonthly.toLowerCase() === "true");
console.log("per month is " + perMonth); //updating perMonth correctly at this point
//guessing I need to do something here or in the function that changes the value of the attribute
//put it here, if you instantiated scope already.
scope.digest();
//scope.apply();
});
hope it works
It seems you want to do something like this jsfiddle?
<form name="ExampleForm">
<select ng-model="period">
<option value="monthly">monthly</option>
<option value="yearly">yearly</option>
</select>
<pre>
period = {{period}}
</pre>
Edit as {{period}}: <input price-monthly="obj.price" period="period" ng-model="obj.price" >
<pre>
price = {{obj.price}}
</pre>
</form>
And JS controller
.controller('ExampleController', function($scope) {
$scope.period = 'monthly';})
And JS directive
.directive('priceMonthly', function() {
return {
restrict: 'A',
scope:{
priceMonthly:"=",
period:"="
},
link: function(scope) {
scope.$watch('period',function(newval){
if(newval=='monthly')
scope.priceMonthly = scope.priceMonthly*12;
if(newval=='yearly')
scope.priceMonthly = scope.priceMonthly/12;
})
}
};});
I hope this will help you.

Undefined value from text area in AngularJS

I am creating one form using Bootstrap & AngularJS. I am using CK editor in my page as textarea. But I am not able to retrieve the value of the textarea while the value of the input text field is easily captured in my AngularJS controller. Following is the code snippet:
HTML page:
<div class="container">
<div ng-controller="controller">
<form role="form">
<label for="sd"><b>Short Description: </b></label>
<input ng-model="sdesc" class = "form-control input-xxlarge" type = "text" placeholder ="Provide a short description here."/>
<br/>
<label for="dt"><b>Details: </b></label>
<textarea ng-model="details" class="form-control" name="details_editor" id="details_editor"></textarea>
<br/>
<button class = "btn btn-primary" ng-click="submitted()">Ask It!</button>
<script>
CKEDITOR.replace('details_editor');
</script>
</form>
</div>
<br/>
<hr>
</div>
JS
app.controller('controller', ['$scope', function($scope){
$scope.submitted = function(){
var sdesc = $scope.sdesc;
var details = $scope.details;
alert($scope.details);
};
}]);
The alert shows undefined for the text area value.
Please help me solve the issue.
You are using the plain Javascript version of CK editor and hence Angular is not getting notified to update the ng-model value of that textarea.
Basically, Angular runs a digest cycle to update all views and models but since in this case the values being changed in the CK editor is happening outside the Angular.s context which is not updating the ng-model value.
To fix this, we added a small directive and notifying the change in the ng-model to the Angular by using the $timeout. (We can also use the $apply directive, but it may fail sometimes if the digest cycle is already in progress)
Example directive:
var app = angular.module("your-app-name", []);
app.directive("ckEditor", ["$timeout", function($timeout) {
return {
require: '?ngModel',
link: function ($scope, element, attr, ngModelCtrl) {
var editor = CKEDITOR.replace(element[0]);
console.log(element[0], editor);
editor.on("change", function() {
$timeout(function() {
ngModelCtrl.$setViewValue(editor.getData());
});
});
ngModelCtrl.$render = function (value) {
editor.setData(ngModelCtrl.$modelValue);
};
}
};
}]);
Remove, your following code:
<script>
CKEDITOR.replace('details_editor');
</script>
And, modify your text-editor like:
<textarea ng-model="details" class="form-control" ck-editor name="details_editor" id="details_editor"></textarea>
I found ng-ckeditor to implement ckeditor in angularjs.
Please refer this :https://github.com/esvit/ng-ckeditor. I tried it, It is easy to implement and working as expected

Apply currency filter to the input field in angularjs

Hi when I am using span tags I can apply the money filter like
<div ng-repeat="item in items">
<span>
{{item.cost | currency}}
</span>
</div>
I am wondering how I can apply same currency filter in input tag. i.e
<div ng-repeat="item in items">
<input type="text" ng-model="item.cost | currency" />
</div>
When I try to apply currency filter to the input field as above it doesnt work. Please let me know how to apply currency filter to input field. Thanks
I created a simple directive that handles formatting input fields. Here is a jsfiddle example. To use it add this to your existing code.
<div ng-repeate="item in items">
<input type="text" ng-model="item.cost" format="currency" />
</div>
And add this directive to your code.
// allow you to format a text input field.
// <input type="text" ng-model="test" format="number" />
// <input type="text" ng-model="test" format="currency" />
.directive('format', ['$filter', function ($filter) {
return {
require: '?ngModel',
link: function (scope, elem, attrs, ctrl) {
if (!ctrl) return;
ctrl.$formatters.unshift(function (a) {
return $filter(attrs.format)(ctrl.$modelValue)
});
elem.bind('blur', function(event) {
var plainNumber = elem.val().replace(/[^\d|\-+|\.+]/g, '');
elem.val($filter(attrs.format)(plainNumber));
});
}
};
}]);
Unfortunately you can not format using ng-model. At least not that way. You will need to create your own directive that implements a parser and formatter. Here is a similar question.
There is a pretty good directive our there that does that currently: ngmodel-format
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-example52-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.14/angular.min.js"></script>
</head>
<body ng-app="">
<script>
function Ctrl($scope) {
$scope.amount = 1234.56;
}
</script>
<div ng-controller="Ctrl">
<input type="number" ng-model="amount"> <br>
default currency symbol ($): <span id="currency-default">{{amount | currency}}</span> <br>
custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
</div>
</body>
</html>
I think you don't need to apply the filter in your input, because in your input you don't need formated currency, take a look at this page https://docs.angularjs.org/api/ng/filter/currency this is the official help for angular currency filter.
If you are using bootstrap, you can use one of these controls http://getbootstrap.com/components/#input-groups-basic
I hope this help.
You can create directive and apply formatting on value and on blur you can set that formatted value to input.
<input format-currency amount="amount">
angular.module('app', [])
.controller('myCtrl', function($scope) {
$scope.amount = 2;
})
.directive('formatToCurrency', function($filter){
return {
scope: {
amount : '='
},
link: function(scope, el, attrs){
el.val($filter('currency')(scope.amount));
el.bind('focus', function(){
el.val(scope.amount);
});
el.bind('input', function(){
scope.amount = el.val();
scope.$apply();
});
el.bind('blur', function(){
el.val($filter('currency')(scope.amount));
});
}
}
});
link http://jsfiddle.net/moL8ztrw/3/
Installation - mat currency-format
$ npm i mat-currency-format
Description
The directive can be used in html input to automatically change the input to locale currency.
Demo
<input type="text"
mvndrMatCurrencyFormat
[allowNegative]="false"
[currencyCode]="'USD'"
[value]="usAmount"
(blur)="updateUSAmount($event)" />
hope this will help,
Cheers !
I found ng-currency to work very well for currency inputs. It supports locale-based decimals and thousands separators, and allows a variable number of decimal digits.
<input type="text" model="yourModel" ng-currency />
I wrote this directive and it helped me to format currency values. I hope it helps someone.
.directive('numericOnly', function(){
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var regex = /^[1-9]\d*(((.\d{3}){1})?(\,\d{0,2})?)$/;
modelCtrl.$parsers.push(function (inputValue) {
var transformedInput = inputValue;
if (regex.test(transformedInput)) {
console.log('passed the expression...');
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
return transformedInput;
} else {
console.log('did not pass the expression...');
transformedInput = transformedInput.substr(0, transformedInput.length-1);
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
return transformedInput;
}
});
}
};
});

ng-options model not updated when use arrow keyboard instead of mouse

I Created js fiddle: Fiddle
I create a form with some ng-options in it, and it have strange behavior when you use the button instead of mouse (just click on the textbox and press "tab" and you can select it using arrow key).
<form ng-controller="MyApp" id="Apps" name="Apps" ng-submit="SendApp()" role="form" novalidate>
<input type="text" name="title" ng-model="Info.Title" />
<select id="Formula" ng-model ="Info.Genre" ng-change= "ChangeGenre()"
ng-options="id as name for (id, name) in Genre" blank></select>
<select class="form-control" ng-model ="Info.Program"
ng-options="Program as Name for (Program, Name) in Program" ng-change="ChangeProgram()" blank></select>
<h3>{{Info.Genre}}</h3>
<h3>{{Info.Program}}</h3>
<button type=submit>Submit this </button>
</form>
Javascript:
var theApp = angular.module("TheApp", []);
theApp.controller("MyApp", ['$scope', function($scope){
$scope.Program = {"1":"Music","2":"Theater","3":"Comedy"};
$scope.Genre = {"1":"Mystery", "2":"Thriller", "3":"Romance"};
$scope.ChangeProgram = function(){
alert($scope.Info.Program + " " + $scope.Info.Genre);
}
$scope.ChangeGenre = function (){
console.log($scope.Info.Genre);
}
$scope.SendApp = function(){
alert($scope.Info.Program + " " + $scope.Info.Genre);
}
}]);
The ng-model are not updated when you select the first options on First try.
What's Wrong, and How To Fix this?
Update:
As Mentioned on comment below, To reproduce, enter mouse into textfield, tab to combobox and try to select the second option (Thriller) using keyboard. This will fail on the first attempt, once the third or first option is selected, the second option is also recognized.
Using the the directive proposed here, this works for me:
theApp.directive("select", function() {
return {
restrict: "E",
require: "?ngModel",
scope: false,
link: function (scope, element, attrs, ngModel) {
if (!ngModel) {
return;
}
element.bind("keyup", function() {
element.triggerHandler("change");
})
}
}
})
I forked the fiddle.

Categories