Unable to use custom directive when ng-model is used - angularjs

While trying to use custom directive with an output linked to text field im getting below issue
[$compile:tplrt] Template for directive 'myDir' must have exactly one
root element.
http://errors.angularjs.org/1.5.0/$compile/tplrt?p0=myDir&p1= can some
one show some light here
Code
<!DOCTYPE html>
<html ng-app="myapp1">
<head>
<title> ANGULAR</title>
<script src="angular.min.js"></script>
<script type="text/javascript">
angular.module('myapp1', []).directive('myDir', function() {
return {
restrict: 'E',
replace: true,
template: '<input type="text" ng-model="title"> {{title}}'
};
});
</script>
</head>
<body>
<div>
<my-dir>sadas</my-dir>
</div>
</body>
</html>

Error message is clear I guess your template should look like this:
<div><input type="text" ng-model="title"> {{title}}</div>
instead of just:
<input type="text" ng-model="title"> {{title}}

You have set your directive replace:true which is deprecated by the way. Since you are replacing element your template should compile to a single root.
If you remove replace attribute, you can use the template you have now. Demo.
directive('myDir', function() {
return {
restrict: 'E',
// don't use deprecated option replace: true
template: '<input type="text" ng-model="title"> {{title}}'
};
});

When a directive is declared with template (or templateUrl) and replace mode on, the template must have exactly one root element. That is, the text of the template property or the content referenced by the templateUrl must be contained within a single html element.
For example,
<p>blah <em>blah</em> blah</p> instead of simply blah <em>blah</em> blah
Otherwise, the replacement operation would result in a single element (the directive) being replaced with multiple elements or nodes, which is unsupported and not commonly needed in practice.
https://docs.angularjs.org/error/$compile/tplrt

Related

Regarding angular js directives usage

i am learning angular so when reading article then some time getting stuck to understand the output. here i confusion of render html output.
code taken from http://www.w3schools.com/angular/tryit.asp?filename=try_ng_directive
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" w3-test-directive></div>
<script>
var app = angular.module("myApp", []);
app.directive("w3TestDirective", function() {
return {
template : "I was made in a directive constructor!"
};
});
</script>
</body>
</html>
when the above code runs then output as follows
<div w3-test-directive="" ng-app="myApp" class="ng-scope">I was made in a directive constructor!</div>
my question is why the directive's template text gets added within start and end div tag ?`
why this attribute is blank w3-test-directive="" in div ?
this text I was made in a directive constructor! could have added in the attribute of w3-test-directive so the html output may look like
<div w3-test-directive="I was made in a directive constructor!" ng-app="myApp" class="ng-scope"></div>
please help me to understand why the directive's template text gets added within start and end div tag ?` thanks
How you use directives depends on the 'restrict' property.
If you add restrict: 'E', then you can use it as a element, ex:
<foo></foo>
If you do restrict: 'A', now its:
<div foo></div>
More info:
http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-i-the-fundamentals
Example:
angular.module('moduleName')
.directive('foo', function () {
return {
restrict: 'EA', //E = element, A = attribute, C = class, M = comment
template: 'Foo'
}
});
The template or the content from templateURL is always inserted between the enclosing tags on which the directive is used. Hence the template text added inside the div tags. This happen because untill it gets to html, it will never be displayed.
w3-test-directive="" : this is because of the fact that this as a attribute has no value. Since it not a known attribute in html, it has no default value, so it will be parsed like this.
I have added an example where i am using the same directive as an element tag instead of using it as a attribute
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp">
<w3-test-directive></w3-test-directive>
</div>
<script>
var app = angular.module("myApp", []);
app.directive("w3TestDirective", function() {
return {
template : "I was made in a directive constructor!"
};
});
</script>
</body>
</html>
A directive renders its template within the element upon which it is declared. The w3-test-directive directive is being declared (as an attribute) on your div element:
<div ng-app="myApp" w3-test-directive></div>
It will therefore render your template within that element's opening and closing tags, and won't (by default) affect anything higher in the DOM tree.
Also, about valueless attributes - they don't need values. For example, the disabled or async attributes do not normally have values. That a particular attribute is merely present is enough, in many cases. In Angular, the presence of a directive, declared as an attribute, is often all that is needed. If you provide values, they will be interpreted as references to model data (handled by the your scope declaration within the directive definition).
why this attribute is blank w3-test-directive="" in div ?
blank space is because it show that attributes as Html5 compliance no html5 errors or warnings. same as if we write disable or readonly property.
ng-directives have menu types to declare for example :
<div ng-app="myApp" w3-test-directive></div>
above example of 'A' means Attribute it can be write as follows:
following example with 'E' Element
<div ng-app="myApp">
<w3-test-directive></w3-test-directive>
</div>
following example with 'C' Class
<div ng-app="myApp">
<span class='w3-test-directive'></span>
</div>
for more info please refer following link:
[angular directives][1]
[1]: https://docs.angularjs.org/guide/directive

$compile service in angular returns an array

I am trying to compile a static DOM against scope using the following code
(function(angular) {
var app = angular.module("directiveModule1",[]);
app.controller('testController', ['$scope', function($scope){
$scope.UserName = "afh";
}]);
app.directive("linkFuncDirective",['$compile', function($compile) {
return {
link: function(scope, element, attrs,controller) {
var markUp = "<input type = 'text' ng-model ='UserName'/>{{UserName}}</br>";
var linkFunc = $compile(markUp);
var content = linkFunc(scope);
angular.element(element).html(content);
//angular.element(element).html($compile(markUp)(scope));
}
};
}]);
})(window.angular);
and my html is below
<html>
<head>
<script data-require="angular.js#*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular.js"></script>
<script src="directiveWithLinkFunction.js"></script>
</head>
<body ng-App="directiveModule1">
<div ng-controller="testController">
<div link-func-directive></div>
</div>
</body>
</html>
and I get the following o/p
[[object HTMLInputElement], [object HTMLSpanElement], [object HTMLBRElement]]
Trying to understand what was written wrong in code, any help is highly appreciated
The reason behind html is having [[object HTMLInputElement], [object HTMLSpanElement], [object HTMLBRElement]] on view is, You have compiled one line of html using $compile service which returns below as compiled DOM
<input type="text" ng-model="UserName">
<span class="ng-binding ng-scope"></span>
<br class="ng-scope">
So basically it has 3 elements, 1st one is input element, 2nd is span & 3rd is br break tag. So when you try to add it as HTML to page using .html method, jQLite internally takes that object and apply .toString() method to making sure it should accept the string. That's the reason why you are getting [Object...] in the output.
Basically your problem is you are assigning compiled angular DOM html content to the directive element html, which wouldn't make sense.
It should be .append function instead of .html as angular compiled DOM will get injected will have binding enabled.
element.append(content); //would append the DOM with angular compiled DOM.
Why do you want to compile that in the first place ? You can use a simple template for that.
Your code is a little bit mess. Try to clean up first.
give a restrict property to your directive
if you don't have a required field then you don't need a controller parameter
Why don't you just simple use a template for your directive

How to embed an html page using angular directive

I am creating an angular.js application.
I have written a html page and wants to put it under div using directive
<div data-(<directive-name)>
</div>
DxPDictionary.directive('import', [function () {
return {
restrict: 'A',
templateUrl: 'template/Import.html',
scope: false,
}
It's not working, is this approch is right or should use another way to achieve this
<body ng-controller="userCtrl">
<div class="container">
<div ng-include="'myUsersList.html'"></div>
<div ng-include="'myUsersForm.html'"></div>
</div>
</body>
use like this.
<div data-directive-name>
</div>
DxPDictionary.directive('dataDirectiveName', [function () {
return {
restrict: 'A',
templateUrl: 'template/Import.html',
scope: false,
}
your directive name dataDirectiveName in directive definition in camel case format and directive name data-directive-name on DOM should match.
You can use ng-include if you are not creating reusable components using directive and want use is as only html of the page.
There is already a directive for this purpose. You do not need to create your own.
https://docs.angularjs.org/api/ng/directive/ngBindHtml
Ashley's answer is good if you keep your html in a file. If you dynamically generate your html, you can use ng-bind-html directive.

ngModel doesn't change the original variable when in a custom directive with ngInclude

The variable inside the directive changes but outside the directive it doesn't change. Here is the actual code:
main.html
<div class="row" ng-repeat="row in template">
<fx-widget type="{{row.type}}" value="post[row.name]"></fx-widget>
{{post[row.name]}}
</div>
app.js
app.directive('fxWidget', function() {
return {
restrict: 'E',
scope: {
value: '='
},
link: function($scope, $element, $attributes) {
$scope.typeUrl = '/partials/' + $attributes.type + '.html';
},
template: '<div ng-include="typeUrl"></div>',
};
});
partials/text.html
<input type="text" ng-model="value">
Here are my tests and notes on finding the problem:
First I tested to see maybe the ngModel doesn't like binding the value through dictionary/array, so I added the following in main.html:
<input ng-model="post[row.name]"> {{post[row.name]}}
This one worked.
I tested to see if the problem is at ng-include by changing the template variable in the directive:
template: '<input ng-model="value">
and this one actually worked, so the problem is in ng-include
After digging deeper I realized that the ng-include doesn't even send the data back to the directive:
template: '<div ng-include="typeUrl"></div> {{value}}'
// ^^ doesn't work
However inside the partial file it works:
partials/text.html
<input type="text" ng-model="value"> {{value}}
What I am guessing is that ng-include creates a copy of the scope and that's why it doesn't change in the parent scope. How can I make it change the scope?
Also an offtopic question. How can I get rid of ng-include alltogether and manually load the partials? The templateUrl parameter can accept a function with attributes but it doesn't compile the data binds to actual variables, so that's out of the question.
Thank you!

Exposing AngularJS directive property value to parent controller

I am working on an AngularJS app. I am trying to write a reusable component to use throughout my app. For the sake of demonstration, we'll just use a text box. I've created a fiddle of my attempt here. Basically, I'm trying to use a control like this:
<div ng-app="myApp">
<div ng-controller="myController">
<my-control textValue="{{controlValue}}"></my-control>
<br />
You entered: {{controlValue}}
</div>
</div>
Unfortunately, I cannot figure out how to bind a property between the scope of the controller and the scope of the directive. I'm not sure what I'm doing wrong in my fiddle. Can someone please tell me what I'm doing wrong?
Thank you!
You have created directive with isolated scope and you are trying to print value from isolate scope. It isn't right, you can write your directive like this, without isolated scope:
return {
restrict: 'EAC',
template: '<input type="text" ng-model="controlValue"></input>'
};
if you want to setup directive with isolated scope, you should isolate your scope then use $watch for do changes
You were not so far, but you need to be carefull when using {{}}
Remove braces and don't use camelNotation for text-value attribute :
<div ng-app="myApp">
<div ng-controller="myController">
<my-control text-value="controlValue"></my-control>
<br />
You entered: {{controlValue}}
</div>
</div>
Use ng-model attribute :
angular.module('ui.directives', []).directive('myControl',
function() {
return {
restrict: 'EAC',
scope: {
textValue: '='
},
template: '<input type="text" ng-model="textValue"></input>'
};
}
);

Resources