Using ngModel.$formatter with non-input elements - angularjs

I've been happily manipulating the view using $parsers and $formatters to transform data in forms. However, when I came to apply the same behaviour to other elements I found it didn't work, as demonstrated here:
angular.module("app", [])
.controller("foo", function ($scope) {
$scope.n = 1;
})
.directive("displayHalf", function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.push(function (value) {
return value*2;
});
ngModel.$formatters.push(function (value) {
return value/2;
});
}
};
});
<!DOCTYPE html>
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body ng-app="app">
<div ng-controller="foo">
<div>
Input: <input type="number" display-half ng-model="n">
</div>
<div>
Span: <span display-half ng-model="n">{{n}}</span>
</div>
<div>
Button: <button display-half ng-model="n">{{n}}</button>
</div>
<div>
Div: <div display-half ng-model"n">{{n}}</div>
</div>
</div>
</body>
</html>
I guess I expected a $formatter to be applied as data is displayed, even if it couldn't be edited. Was I mistaken? Any way to get this working without writing {{n / 2}} all over the place?

Related

autocomple in angular js getting error

I am not familiar with angular js for doing demo about autocomplete on angular js; it getting error about autocomplete is not functiion; see below code:
<html>
<head>
<title>Autocomplete Demo</title>
<link rel="stylesheet" href="style/style.css">
<link rel="stylesheet" href="style/autocomplete.css">
</head>
<body>
<header>
<h1><span class="thin">AngularJS:</span> - Demo</h1>
</header>
<div ng-app='MyModule'>
<div ng-controller='DefaultCtrl'>
<input type="text" ng-model="foo" auto-complete /> Foo = {{foo}}
</div>
</div>
<footer>
made by
</footer>
<script src="scripts/angular.min.js"></script>
<script type="text/javascript">
angular.module('MyModule', []).controller('DefaultCtrl', ['$scope', function($scope) {}])
.factory('autoCompleteDataService', [function() {
return {
getSource: function() {
return ['apples', 'oranges', 'bananas'];
}
}
}])
.directive('autoComplete', function(autoCompleteDataService) {
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.autocomplete({
source: autoCompleteDataService.getSource(),
minLength: 2
});
}
};
});
</script>
I have tried my best and surfing on the google as well as stackoverflow but I didn't get the solution.
See error image autocomplete is not a function :

tooltip in angularjs with "uib-tooltip-html"

I try to implement a tooltip with angularjs template inside. For this, I use "uib-tooltip-html" and I add an attribute on the element to compile the template. But it doesn't work.
Here is the code
Here is the plunker
http://plnkr.co/edit/y1TvogsFFBoBVra3gO3F?p=preview
<html>
<head lang="en">
<meta charset="UTF-8"/>
<title>uib-tooltip-html test</title>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.js"></script>
<script src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.14.3.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular-sanitize.min.js"></script>
<script>
var app = angular.module("test", ['ngSanitize','ui.bootstrap']).config(function($sceProvider) {
$sceProvider.enabled(false);
});
app.controller("testController", function($scope, $http, $interval, $sce) {
$scope.text = $sce.trustAsHtml('<table><tr ng-repeat="x in [1,2,3]"><td>{{ x }}</td></tr></table>');
});
app.directive('compileTemplate', function($compile, $parse){
return {
link: function(scope, element, attr){
var parsed = $parse(attr.uibTooltipHtml);
console.log(attr.uibTooltipHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
console.log(getStringValue())
//Recompile if the template changes
scope.$watch(getStringValue, function() {
console.log('ca passe');
$compile(element, null, -9999)(scope); //The -9999 makes it skip directives so that we do not recompile ourselves
});
}
}
});
</script>
</head>
<body>
<div ng-app="test" ng-controller="testController">
<p style="margin-top: 5em;" uib-tooltip="Some text" >
A Thing With a Tooltip
</p>
<p style="margin-top: 5em;" uib-tooltip-html="text" compile-template>
A Thing With an HTML Tooltip
</p>
</div>
Thank you in advance for your answer
You can use uib-tooltip-template like this:
<p style="margin-top: 5em;" uib-tooltip-template="'myTooltipTemplate.html'">
A Thing With an HTML Tooltip
</p>
And then in put your html in myTooltipTemplate.html:
<table><tr ng-repeat="x in [1,2,3]"><td>{{ x }}</td></tr></table>
The template goes in a separate file.
documentation: https://angular-ui.github.io/bootstrap/#/tooltip
plnkr: http://plnkr.co/edit/tiCHpd0LipixXbO4Xfa5?p=preview

Angular, how to select the contents of a text input, with onClick() event on a button?

I am newbie to Angular and web development, I have a text input area that needs to be selected (highlighted) when a button is clicked in Angular.
do I need to something like angular.element(document.getElelmentById(txt1)) and do select on it?
Similar to this thread:
Selecting all text in HTML text input when clicked , the question is, is there a rightway/better way to do this in Angular?
I have searched for an answer, closest I could get was this thread: How to set focus on input field? but couldn't successfully convert the suggestions for select().
Here is my jsfiddle in plain js: http://jsfiddle.net/x62ye14y/, a translation to angular would be greatly appreciated.
<!DOCTYPE html>
<html>
<body>
Select your favorite fruit:
<input type="text" id="id123" placeholder="ENTER VALUE">
<p>Click the button to select text in the textbox</p>
<button onclick="myFunction()">Select Txt</button>
<script>
function myFunction() {
document.getElementById("id123").select();
}
</script>
</body>
</html>
Here is the code I have so far,:
<!DOCTYPE html>
<html ng-app="demo">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
</head>
<body>
<div ng-controller="DemoCtrl">
<input type="text" ng-model="content" id="txt1"/>
<button ng-click="selectOnClick()">Select Txt</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js">
</script>
<script type="text/javascript">
var mod1 = angular.module('demo', []);
mod1.controller('DemoCtrl', function ($scope) {
$scope.content = 'some text';
});
mod1.directive('selectOnClick', function () {
// Linker function
var element1 = angular.element("txt1");
element1.select();
});
</script>
</body>
</html>
http://plnkr.co/edit/DKxAs4QfkLzwAYPxx7tW?p=preview
Simple way to do is using click event.
for example
<input type = "text" (click) = "$event.target.select()">
Can you try this:
http://plnkr.co/edit/PzcINVKw6KNBFxlZUgAS?p=preview
<!DOCTYPE html>
<html ng-app="demo">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
</head>
<body>
<div ng-controller="DemoCtrl">
<input type="text" ng-model="content" select-on-click />
<p>Content: {{content}}</p>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
app:
(function (angular) {
var module = angular.module('demo', []);
module.controller('DemoCtrl', function ($scope) {
$scope.content = 'foobar';
});
module.directive('selectOnClick', function () {
// Linker function
return function (scope, element, attrs) {
element.bind('click', function () {
this.select();
});
};
});
}(angular));
you just need to move the select-on-click to a button

How to capture ng-model with the ng-bind?

I'm not able to make the ng-bind="data1" capture the input ng-model="data1" from the widget. By clicking and choosing a date, ng-bind is not capturing the chosen date.
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" media="screen" href="http://tarruda.github.com/bootstrap-datetimepicker/assets/css/bootstrap-datetimepicker.min.css">
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.2.27/angular.min.js"></script>
<script type="text/javascript" src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js"></script>
<script type="text/javascript" src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.min.js"></script>
<script type="text/javascript" src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.pt-BR.js"></script>
<script type="text/javascript">
var Module = angular.module('myapp', []);
myApp.directive('myapp', function datetimepicker() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
element.datetimepicker({
minView: 2,
autoclose: true,
language: 'pt',
format: 'dd/mm/yyyy',
showMeridian: true,
startView: 2
})
.find('input')
.addClass("form-control");
}
};
});
</script>
</head>
<body ng-app="myapp">
<div id="datetimepicker" class="input-append date" ng-model="data1">
<input ng-model="data1" type="text" datetimepicker></input>
<p ng-bind="data1">
<span class="add-on">
<i data-time-icon="icon-time" data-date-icon="icon-calendar"></i>
</span>
</div>
</body>
</html>
You should not give the same name myapp to your module and your directive.
Nowhere in your html you are using the directive.
Also, a <div> cannot have a ng-model directive, so this line is wrong:
<div id="datetimepicker" class="input-append date" ng-model="data1">
Your problem is that you need to initialize data1 in your controller:
function($scope) {
// Initialization
$scope.data1 = '';
}

AngularJS - Create a directive that adds a sibling element

I'm creating a my-validate directive that looks something like this
<input my-validate="customValidation" ng-model="model" />
What I want to do is to attach a sybling element to the directive like this
Error template:
<ul class"errors">
<li ng-repeat="for error in errors">{{error}} not valid</li>
</ul>
errors is defined in the scope of the directive.
I've added the error template in the compile function, but the problem I have is that the scope in the link function is not the same as the attached template.
Here is a plunker to illustrate the issue: http://plnkr.co/edit/ghdtdYruQaaO0Yxxlrt1?p=preview
'world' is seen in the directive template, but not on the added element :S.
That's because your div "2 hello" is outside the container where your scope is visible.
you can use element.append() instead of element.after() to have the scope available.
Directive
var app = angular.module('plunker', []);
app.directive('myValidate', function($compile) {
return {
template: '<span>1. Hello {{world}} my scope is {{$id}} (parent: {{$parent.$id}})<span/>',
replace: true,
restrict: 'A',
scope: true,
compile: function (element) {
element.append('<div>2. Hello {{ world }}, my scope is {{$id}} (parent: {{$parent.$id}})</div>');
return function(scope) {
scope.world = 'World';
//$compile()(scope);
};
}
};
});
HTML
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script data-require="angular.js#1.1.5" data-semver="1.1.5" src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="app.js"></script>
</head>
<body>
<input my-validate="" />
</body>
</html>
http://plnkr.co/edit/dU3holBCePKe0ZAwQKh1?p=preview
I was reading and checking the example because I was in the same situation to display validation messages but under the input field and the message can change according to what kind of validation is required.
So I came up with this solution
var app = angular.module('app', []);
app.controller('ctrl', function($scope, CONSTANTS) {
$scope.title = "title";
$scope.CONSTANTS = CONSTANTS;
});
app.constant('CONSTANTS', {
LENGHT_1: 3,
LENGHT_2: 4
});
app.directive('dir', function($compile) {
return {
scope: true,
restrict: 'A',
require: '?ngModel',
link: function(scope, elem, attrs, ngModel) {
scope.maxLength = false;
scope.required = false;
scope.max = scope.$eval(attrs['ngMaxlength']);
var tpl = '<div ng-if="maxLength" ng-include="\'length.tpl.html\'"></div>' +
'<div ng-if="required" ng-include="\'required.tpl.html\'"></div>';
var el = $compile(tpl)(scope);
elem.after(el);
scope.$watch(attrs['ngModel'], function(newValue, oldValue, scope) {
if (ngModel.$error !== null && ngModel.$error.maxlength) {
scope.maxLength = true;
} else {
scope.maxLength = false;
}
if (ngModel.$error !== null && ngModel.$error.required && ngModel.$dirty) {
scope.required = true;
} else {
scope.required = false;
}
});
}
}
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.4.7" data-semver="1.4.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script type="text/ng-template" id="length.tpl.html">
max length {{max}}
</script>
<script type="text/ng-template" id="required.tpl.html">
required
</script>
</head>
<body ng-controller="ctrl">
<h1>Input Validation</h1> {{title}}
<br><br>
<form name="form" novalidate>
<input dir name="input_one" ng-model="bar" ng-maxlength="CONSTANTS.LENGHT_1" required>
<br>
input one: {{form.input_one.$error}}
<br>
<br>
<input dir name="input_two" ng-model="foo" ng-maxlength="CONSTANTS.LENGHT_2">
</form>
<br>
input two: {{form.input_two.$error}}
</body>
</html>
On Plunkr
Hope it helps.
I think you're on the right track by using the form errors to toggle display. That's exactly how it's recommended in the standard Angular documentation.
If you'd like to show multiple errors for a single input, however, and possible even control the error messages from there, I'd recommend utilizing a service, such as implemented at http://plnkr.co/edit/iNcNs2ErrOnYf9I7whdu?p=preview.
Right now you can have one message per token, but as many tokens as you want per input. If you want multiple messages per token, just use an array of messages instead of single string value (note, unset does become more complicated with that method).
Hope that helps,
Alex

Resources