I break my head try to resolve this problem. Suppose that I have this custom directive:
app.directive("selectInput",function($compile){
return {
restrict: "E",
templateUrl: 'js/angular-app/test.html',
scope: {
formName:'=',
inputName:"=",
nameInput: "#",
ngModel: "=",
},
transclude: true,
replace: true,
link: function(scope, element, attrs, ctrl) {
...
},
}});
Here my templateurl test.html
<div
class="form-group"
ng-class="{'has-error has-feedback': formName.inputName.$invalid}">
<input type="text" name="{{nameInput}}" ng-model="ngModel"/></div>
And the call
<form name="form" class="simple-form" novalidate>
<select-input
form-name="form"
input-name="fClase"
name-input="fClase"
ng-model="inputmodel">
</select-input></form>
The problem is in test.html template, the expression formName.inputName.$invalid not work, I try {{formName}}.{{inputName}}.$invalid and nothing, also I try change the params in directive definition for &, # ... =?.
I have not been able to merge this expressions, I appreciate any help.
Update, fix the problem (Thanks to Joe Enzminger):
At the end I change the directive by this:
app.directive("selectInput",function($compile){
return {
restrict: "E",
templateUrl: 'js/angular-app/test.html',
scope: {
inputName: "#",
ngModel: "=",
},
require: ["^form"],
replace: true,
link: function(scope, element, attrs, ctrl) {
scope.form = ctrl[0];
...
},
}});
Note the form attr as ctrl.
The template test.html
<div
class="form-group"
ng-class="{'has-error has-feedback': form[inputName].$invalid}">
<input type="text" name="{{nameInput}}" ng-model="ngModel"/></div>
Here change formName.inputName.$invalid by form[inputName].$invalid
And finally the call
<form name="form" class="simple-form" novalidate>
<select-input
input-name="fClase"
ng-model="inputmodel">
</select-input></form>
I hopefully useful
Here is an alternative implementation that might clarify how things actually work.
The changes:
Don't inject $compile (you don't use it)
No transclude: true (you aren't using transclusion)
scope: {} - we create an empty isolate scope so that our template will work and we can isolate the directive scope from the parent scope.
require: ["ngModel", "^form"] - we want to require ngModel on the element and require that the element is embedded in a form. These will be delivered to the link functions ctrl parameter.
<div
class="form-group"
ng-class="{'has-error has-feedback': form[model.$name].$invalid}">
<input type="text" ng-model="model.$modelValue"/></div>
<form name="form" class="simple-form" novalidate>
<select-input
ng-model="inputmodel">
</select-input></form>
app.directive("selectInput",function(){
return {
restrict: "E",
templateUrl: 'js/angular-app/test.html',
scope: {},
replace: true,
require: ["ngModel", "^form"],
link: function(scope, element, attrs, ctrl) {
//give our directive scope access to the model and form controllers
$scope.model = ctrl[0];
$scope.form = ctrl[1];
},
}});
Related
How i can show/hide directive when some elements in parent controller has event?
app.directive('rest', function(){
return {
restrict: 'E',
scope: false,
replace: true,
link: function(scope, elem, attr) {
},
templateUrl: '<div ng-show="showDirective"></div>',
}
});
<div ng-controller="AppCtrl">
<rest></rest>
<div ng-click="showDirective = false"><div> <!-- hide directive -->
<div ng-click="showDirective = true"><div> <!-- show directive -->
</div>
Here, your mistake was "templateUrl" instead of "template". When you provide html inline, user "template", when you provide html in a separate html file, use "templateUrl" and provide a url to the template html:
http://plnkr.co/edit/xzqOvcjKYfWxazWfHWyS?p=preview
.directive('rest', function(){
return {
restrict: 'E',
scope: false,
replace: true,
link: function(scope, elem, attr) {
},
template: '<div ng-if = "showDirective" >Test</div>',
}
I've created a directive pgPaginator:
function PaginatorDirective() {
return {
restrict: 'E',
require: 'ngModel',
templateUrl: 'paginator.html',
scope: {
ngModel: '=',
},
};
}
// ...
.directive('pgPaginator', PaginatorDirective)
paginator.html:
<input pg-paginator-page />
<select pg-paginator-perpage ng-model="ngModel.perpage" ng-options="option for option in ngModel.perpageOptions"></select>
<br />
{{ngModel}}
<br />
{{ngModel.page}}
and i tryed to create another directive pg-paginator-page that use pgPaginator scope:
.directive('pgPaginatorPage', function() {
return {
restrict: 'A',
replace: true,
template: '<input ng-model="ngModel.page" type="number" />',
link: function(scope, element, attrs) {
console.log(scope)
},
}
})
But when I create this directive, two-way binding is broken: http://embed.plnkr.co/h85hAk/preview
What am I doing wrong?
In the following AngularJS code, when you type stuff into the input field, I was expecting the div below the input to update with what is typed in, but it doesn't. Any reason why?:
html
<div ng-app="myApp">
<input type="text" ng-model="city" placeholder="Enter a city" />
<div ng-sparkline ng-model="city" ></div>
</div>
javascript
var app = angular.module('myApp', []);
app.directive('ngSparkline', function () {
return {
restrict: 'A',
require: '^ngModel',
template: '<div class="sparkline"><h4>Weather for {{ngModel}}</h4></div>'
}
});
http://jsfiddle.net/AndroidDev/vT6tQ/12/
Add ngModel to the scope as mentioned below -
app.directive('ngSparkline', function () {
return {
restrict: 'A',
require: '^ngModel',
scope: {
ngModel: '='
},
template: '<div class="sparkline"><h4>Weather for {{ngModel}}</h4></div>'
}
});
Updated Fiddle
It should be
template: '<div class="sparkline"><h4>Weather for {{city}}</h4></div>'
since you are binding the model to city
JSFiddle
The basic issue with this code is you aren't sharing "ngModel" with the directive (which creates a new scope). That said, this could be easier to read by using the attributes and link function. Making these changes I ended up with:
HTML
<div ng-sparkline="city" ></div>
Javascript
app.directive('ngSparkline', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var newElement = '<div class="sparkline"><h4>Weather for {{' + attrs.ngSparkline + '}}</h4></div>';
element.append(angular.element($compile(newElement)(scope)));
}
}
});
Using this pattern you can include any dynamic html or angular code you want in your directive and it will be compiled with the $compile service. That means you don't need to use the scope property - variables are inherited "automatically"!
Hope that helps!
See the fiddle: http://jsfiddle.net/8RVYD/1/
template: '<div class="sparkline"><h4>Weather for {{city}}</h4></div>'
the issue is that require option means that ngSparkline directive expects ngModel directive controller as its link function 4th parameter. your directive can be modified like this:
app.directive('ngSparkline', function () {
return {
restrict: 'A',
require: '^ngModel',
template: '<div class="sparkline"><h4>Weather for {{someModel}}</h4></div>',
link: function(scope, element, attrs, controller) {
controller.$render = function() {
scope.someModel = controller.$viewValue;
}
}
}
});
but this creates someModel variable in scope. that I think isn't necessary for this use case.
fiddle
So, have created a few angular directives -- picture "user controls" around common data entry elements, like a label-textbox pair, etc
The problem we are having is that the zValidate directive does not seem to work from within the directive. Is there something we need to do to make nested directives work?
Edit
Here are the relevant code snippets.
So, first, we have a little directive that adds a label-input pair:
app.directive('afLabelInputPair', function ($compile) {
var directive = {
restrict: 'A',
transclude: true,
replace: true,
scope: { //#textValue =twoWayBinding &oneWayBinding
labelText: '#labelText',
afModel: '=',
afId: '#',
afPlaceholder: '#'
},
templateUrl: './app/templates/af-label-input-pair.html',
link: function (scope, element, attrs) {
scope.opts = attrs;
$compile(element.contents())(scope);
}
}
return directive;
});
Next, we have the template html (this is what's returned from templateUrl:
<div class="form-group">
<label class="control-label" for="{{afId}}">{{labelText}}</label>
<input id="{{afId}}" class="form-control" ng-model="afModel" placeholder="{{afPlaceholder}}" data-z-validate />
</div>
But, we don't get a display of breeze validation errors when we use this directive.
I'm trying to create a custom component that uses a dynamic ng-model inside-out the directive.
As an example, I could invoke different components like:
<custom-dir ng-model="domainModel1"></custom-dir>
<custom-dir ng-model="domainModel2"></custom-dir>
With a directive like:
app.directive('customDir', function() {
return {
restrict: 'EA',
require: '^ngModel',
scope: {
ngModel: '=dirValue',
},
template: '<input ng-model="dirValue" />',
link: function(scope, element, attrs, ctrl) {
scope.dirValue = 'New';
}
};
});
The idea is that the textbox from the directive would change if the model changes, and in the other way around.
The thing is that I've tried different approaches with no success at all, you can check one of this here: http://plnkr.co/edit/7MzDJsP8ZJ59nASjz31g?p=preview In this example, I'm expecting to have the value 'New' in both of the inputs, since I'm changing the model from the directive and is a bi-directional bound (=). But somehow is not bound in the right way. :(
I will be really grateful if someone give some light on that. Thanks in advance!
Something like this?
http://jsfiddle.net/bateast/RJmhB/1/
HTML:
<body ng-app="test">
<my-dir ng-model="test"></my-dir>
<input type="text" ng-model="test"/>
</body>
JS:
angular.module('test', [])
.directive('myDir', function() {
return {
restrict: 'E',
scope: {
ngModel: '='
},
template: '<div><input type="text" ng-model="ngModel"></div>',
};
});