Here is the directive:
(function () {
'use strict';
angular
.module('utils')
.directive('phoneNumberInputFormat', phoneNumberInputFormat);
phoneNumberInputFormat.$inject = ['$filter'];
function phoneNumberInputFormat($filter) {
return {
link: link,
scope: {
model: '=ngModel'
},
restrict: 'A'
};
function link(scope, element, attributes) {
scope.$watch('model', function (value, oldValue) {
var number = String(value).replace(/[^0-9]+/g, '');
scope.model = $filter('phoneNumber')(number);
});
}
}
})();
I am trying to basically modify the value in a textbox to look like a standard telephone number. I use this directive as an attribute on a textbox. The problem is that the scope.model is either "" or undefined all the time. I expect it to point to the property that the textbox is modeling so that, as the value changes , this directive is formatting the telephone number correctly.
html:
<input phone-number-input-format name="phone"
ng-minlength="14"
ng-maxlength="14"
ng-change="vm.phoneOrEmail()"
class="form-control form-group-lg"
placeholder="Phone Number"
type="tel"
ng-model="vm.registrant.HOME_PHONE_NR">
Your code is just fine. The reason you don't see model changes is because you limited your input to exactly 14 characters. This means angular will change your model only when the limitations are met, AKA: 14 characters. if you'll set ng-minlength="1" you'll see your changes on each typed characters.
See: Working Example
I have a simple directive using isolate scope which passes data to a scoped method from within the template:
app.directive("phone", function () {
return {
scope: {
dial: "&"
},
template: '<input type="text" ng-model="value">' +
'<br>' +
'<div class="button" ng-click="dial({message:value})">' +
'Call home!</div>',
controller: function($scope) {
console.log($scope);
}
};
});
Works fine. But I'd like to clear the input field after the alert has been completed. I'm having a hard time figuring out how I can access ng-model="value" on that input that is generated from within the directive. Any help?
Here's a plunk for you
change the template to this
template: '<input type="text" ng-model="value">' +
'<br>' +
'<div class="button" ng-click="dial({message:value}); value = \'\' ">' +
'Call home!</div>',
note that ng-click is changed to ng-click="dial({message:value}); value = \'\' "
this will sets the value to empty string after calling the dial() function.
here is the demo
or you can try something this, but seems like first one is the better one.
I'm creating inputs inside a form dynamically. I created this directive for the purpose:
// Generate inputs on the fly using BE data.
.directive('inputGenerator', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
id: '#',
type: '#',
name: '#',
attributes: '=',
ngModel: '=',
ngDisabled: '='
},
link: function (scope, iElement, iAttrs) {
// Get attributes
var id = iAttrs.id,
type = iAttrs.type,
name = iAttrs.name;
scope.ngModel[name] = {};
var extended_attributes = {
"type": type,
"id": id,
"data-ng-model": 'ngModel.' + name + '[\'value\']',
"name": name,
"data-ng-disabled": "ngDisabled"
};
if ( ! scope.attributes) {
scope.attributes = {};
}
// Append extra attributes to the object
angular.extend(scope.attributes, extended_attributes);
// Generate input
var input = '<input ';
angular.forEach(scope.attributes, function (value, key) {
input += key + '="' + value + '" ';
});
input += '/>';
// Compile input element using current scope (directive) variables
var compiledElement = $compile(input)(scope);
// Set the file selected name as the model value
compiledElement.on('change', function () {
if (this.files && this.files[0].name) {
var that = this;
scope.$apply(function () {
scope.ngModel[name] = {};
scope.ngModel[name]['value'] = that.files[0].name;
});
}
});
// Replace directive element with generated input
iElement.replaceWith(compiledElement);
}
};
}]);
This html line will trigger the directive:
<input-generator data-name="{{ item.name }}" data-ng-model="inputs.sources" data-attributes="item.attrs" data-type="{{ item.type }}" data-id="inputFile_{{ $index }}" data-ng-disabled="inputs.sources[item.name].selected" />
I'm running on Angular 1.4.3.
Problem
The model and pretty much everything works fine in the directive, but for some reason the form remains valid when the input added is invalid as you can see in this image.
I already tried:
Any of the Angular features of form validation works
I debugged Angular and seems to be that the input attached to the form is different from the input compiled inside the directive.
I already called formName.$setPristine() after each input was created, but it didn't work.
I couldn't access the form from the directive, but I think is not a good idea either.
I already wrapped the input with a ng-form tag, but nothing useful comes out of that.
I tried to use the directive compile method, but this is just triggered once when the app loads and I've a select input that loads different inputs on change.
Any help on this is much appreciated! :)
Thank you to everyone for contribute anyways!!
You should definitely take a look at my Angular-Validation Directive/Service. It as a ton of features and I also support dynamic inputs validation, you can also pass an isolated scope which helps if you want to not only have dynamic inputs but also have dynamic forms, also good to use inside a modal window.
For example, let's take this example being a dynamic form and inputs defined in the Controller:
$scope.items.item1.fields = [
{
name: 'firstName',
label:'Enter First Name',
validation:"required"
},
{
name: 'lastName',
label: 'Enter Last Name',
validation:"required"
}
];
$scope.items.item2 = {
heading:"Item2",
formName:"Form2"
};
$scope.items.item2.fields = [
{
name: 'email',
label:'Enter Email Id',
validation:"required"
},
{
name: 'phoneNo',
label: 'Enter Phone Number',
validation:"required"
}
];
It will bind the validation to the elements and if you want to easily check for the form validity directly from the Controller, simply use this
var myValidation = new validationService({ isolatedScope: $scope });
function saveData() {
if(myValidation.checkFormValidity($scope.Form1)) {
alert('all good');
}
}
You can also use interpolation like so
<input class="form-control" type="text" name="if1"
ng-model="vm.model.if1"
validation="{{vm.isRequired}}" />
Or using a radio/checkbox to enable/disable a field that you still want to validate when it becomes enable:
ON <input type="radio" ng-model="vm.disableInput4" value="on" ng-init="vm.disableInput4 = 'on'">
OFF <input type="radio" ng-model="vm.disableInput4" value="off">
<input type="text" name="input4"
ng-model="vm.input4"
validation="alpha_dash|min_len:2|required"
ng-disabled="vm.disableInput4 == 'on'" />
It really as a lot of features, and is available on both Bower and NuGet (under the tag name of angular-validation-ghiscoding). So please take a look at my library Angular-Validation and a live demo on PLUNKER.
It's loaded with features (custom Regex validators, AJAX remote validation, validation summary, alternate text errors, validation on the fly with the Service, etc...). So make sure to check the Wiki Documentation as well... and finally, it's fully tested with Protractor (over 1500 assertions), so don't be afraid of using in production.
Please note that I am the author of this library
I ran into this issue as well with Angular v1.5.9. The main issue here is that you are compiling the HTML template before it is in the DOM, so Angular doesn't know it's part of the form. If you add the HTML first, then compile, Angular will see your input as a form child, and it will be used in the form validation.
See similar answer to Form Validation and fields added with $compile
Don't do:
var myCompiledString = $compile(myHtmlString)(scope);
// ...
element.replaceWith(myCompiledString);
Do this instead:
var myElement = angular.element(myHtmlString)
element.replaceWith(myElement) // put in DOM
$compile(myElement)(scope) // $compile after myElement in DOM
Note: I swapped the more conventional element for OP's iElement, which is a jQLite reference of the directive's HTML element
you need to use ng-form directive as a wrapper for your input.
you can see an example of this here
but it works for me. You can pass the form reference to the directive and use it directly.
in the code below, the scope.form is used to know the general state of the form, and the scope.name to access the input field state.
< ng-form name="{{name}}" ng-class="{error: this[name][name].$invalid && form.$submitted}" >
i hope it helps
you need to set name of control dynamic and use this dynamic name for form validation. in the following e.g. you see the dynamic name and id of control and used for the validation of angular (using ng-massages)
more details see http://www.advancesharp.com/blog/1208/dynamic-angular-forms-validation-in-ngrepeat-with-ngmessage-and-live-demo
Field Num Is Required.
I transform FCKTAG to INPUT and attach dhtmlxcalendar. It works.
Directive works fine too.
But I need attach calendar to an input with an icon Initialization of dhtmlxCalendar Doc
Initialization of dhtmlxCalendar Doc: I must put in
<span><img id="calendar_icon" src="path.gif" border="0"></span>
In Angular Directive I put
template: '<input type="text" ng-model="g" ></input>' +
'<span><img src="http://clans.worldoftanks.ru/media/' +
'clans/emblems/cl_582/2582/emblem_24x24.png" border="0"></span>',
It's error. I need one root tag. I choose DIV:
template: '<div>' +
'<input type="text" ng-model="g" ></input>' +
<span><img src="http://clans.worldoftanks.ru/media/' +
'clans/emblems/cl_582/2582/emblem_24x24.png" border="0"></span>' +
'</div>',
Annnd... Calendar doesn't load.
I haven't any idea why it.
plunker without an icon
plunker with an icon DOESN'T WORK
In your link function you are get the input element using element[0]. Once you wrap all of it in a div tag it is no longer element[0]. Trying substituting the following code.
var input = element.find('input')[0];
if (myCalendar == null) {
myCalendar = new dhtmlXCalendarObject(input);
} else {
myCalendar.attachObj({input:input, button: input});
}
updated plunker
I am trying to generate an HTML templaye from AngularJS directive but I'm not able to pass any object into a function within one of the generated elements. This is my directive:
app.directive('listObject', function($compile){
return {
scope : {
obj : "="
},
controller: "httpPostController",
link : function(scope, element) {
scope.elementTree = null;
//recursivly generate the object output
scope.printObject = function (field, content) {
if (field){
content = "<div>"
if (field.isRequired){
content += "<p>" + field.name + "*:</p>";
} else {
content += "<p>" + field.name + ":</p>";
}
if (field.isEnum){
content += '<select ng-model="createEntityResource[field.name]" ng-change="getCreateEntityAsText()" class="form-control">' +
'<option></option>' +
'<option ng-repeat="enumValue in field.enumValues" label={{enumValue.name}}>{{enumValue.ordinal}}</option>' +
'</select>';
} else if (field.restResourceName) {
content += '<button type="button" ng-click="loadResourceFieldsForField(field)">Create new</button>';
// content += "<p>"+i+""+scope.printObject(field)+"</p>";
} else {
content += '<input type="text" ng-model="createEntityResource[' + field.name + ']" ng-change="getCreateEntityAsText()"' +
'class="form-control" placeholder="{{parseClassName(field.type)}}">';
}
content+="</div>";
return content;
}
};
scope.refresh = function (){
if(scope.elementTree){
scope.elementTree.remove();
}
//generate the html into a string
var content = scope.printObject(scope.obj, content);
//make elements out of a string
scope.elementTree = angular.element(content);
compiled = $compile(scope.elementTree);
element.append(scope.elementTree);
compiled(scope);
};
scope.refresh();
}
};
});
When I create a <button> element - I give it a ng-click function. The function is called and works fine, except that the param it is passed (field) is always undefined.
Does anyone know how to pass object into function within an AngularJS directive?
Every useful answer is highly appreciated and evaluated.
Thank you.
P.S. I tried to split the definition of the button to :
'<button type="button" ng-click="loadResourceFieldsForField(' + field + ')">Create new</button>';
but this does not seem work, AngularJS argues about [Object object] being passed to a function.
P.P.S I also tried to make it according to documentation which says:
Often it's desirable to pass data from the isolated scope via an
expression and to the parent scope, this can be done by passing a map
of local variable names and values into the expression wrapper fn. For
example, if the expression is increment(amount) then we can specify
Blockquote
the amount value by calling the localFn as localFn({amount: 22}).
So it looks like this, but field is still undefined:
'<button type="button" ng-click="loadResourceFieldsForField({field: field})">Create new</button>';
So my printObject algorithm worked great :)
`<button type="button" ng-click="loadResourceFieldsForField(' + field + ')">Create new</button>`
The problem here is: You are generating a string.
And you print your object into the string. This will call toString within the object and won't do what you want to do. It will just print "loadResourceFieldsForField([Object])"
`<button type="button" ng-click="loadResourceFieldsForField({field: field})">Create new</button>`
The field property in the string doesn't have any reference to your param field in the method.
Within $compile: angularjs will search for a variable field within the scope and won't find any.
You have to place this field in the scope, to make this work as aspected. But it seems not like a easy job there.
I would try this:
$compile in each printObject with an own $scope.$new containing the field variable.