angular template directive not working - javascript

i have this route in angular
when('/customers', {
//templateUrl: 'customers.html'
controller: 'ListController'
, template: "<h1>{{customers}}</h1>"
})
this works and it displays properly.i decide to go a bit bigger
when('/customers', {
//templateUrl: 'customers.html'
controller: 'ListController'
, template: "<div class=\"navigation-section\" id=\"customers\">\r\n <div class=\"section\">\r\n <div class=\"text-input-container card\"> <i class=\"icon-search text-input-icon\"><\/i>\r\n <input type=\"text\" class=\"text-input \" placeholder=\"Search\" ng-model=\"query1\" \/> <\/div>\r\n <div> <\/div>\r\n <\/div>\r\n <div class=\"section\">\r\n <ul class=\"list\">\r\n <li ng-repeat=\"customer in customers | filter:query1 | orderBy:[\'customer.information.name\',\'customer.information.phone\']\" ripple>\r\n <a href=\"#\/customer\/{{customers.indexOf(customer)}}\"><\/a>\r\n <button class=\"icon-button\"><i class=\"icon-account-circle\"><\/i><\/button> <span class=\"item-text\">\r\n\t\t\t{{customer.information.name}}\r\n\t\t\t<span class=\"secondary-text\">\r\n\t\t\t\t{{customer.information.phone}}\r\n\t\t\t<\/span> <\/span> <i class=\"icon-message item-action\"><\/i> <\/li>\r\n <\/ul>\r\n <\/div>\r\n<\/div>"
})
this doesnt work why?

It is better to put the template in a file and load with templateUrl. However if you really, really need to implement it with raw template then you can use single quotes instead of double ones, so you do not have to escape the double quotes inside a template string, so sth like that:
...
template: '<div class="navigate-section"></div>',
...
You can also try and do sth like:
...
template: [
'<div class="navigate-section">',
'<span>Text</span>',
'</div>'
].join('')
...
I think it should work and will increase readabilty a bit.
You can also add templates to cache as for example angular ui boostrap does it when you include single js file with templates, the tpls.js one.
It is sth like this:
angular.module('my/template/name.html', [])
.run(['$templateCache', function($templateCache) {
$templateCache.put(
'my/template/name.html', '<div class="my-class"><span>Text</span></div>'
);
}]);
You can also include in your main html file where your angular app runs the template as script with ng-template so you put
<script type="text/ng-template" id="/template.html">
<p>
My template
</p>
</script>
and then, pass as templateUrl the string you put as id in script tag
...
templateUrl: '/template.html',
...
One of this methods, should resolve your issue. But still I would recomend loading templates for directives from files.

Angular doesn't expect all the escaped whitespace characters you have in your template. Try this version that's encapsulated in single quotes, has \r\n\t's removed, and does not escape backslashes:
when('/customers', {
//templateUrl: 'customers.html'
controller: 'ListController',
template: '<div class="navigation-section" id="customers"><div class="section"><div class="text-input-container card"> <i class="icon-search text-input-icon"></i><input type="text" class="text-input" placeholder="Search" ng-model="query1" /> </div><div> </div></div><div class="section"><ul class="list"><li ng-repeat="customer in customers | filter:query1 | orderBy:[\'customer.information.name\',\'customer.information.phone\']" ripple><button class="icon-button"><i class="icon-account-circle"></i></button> <span class="item-text">{{customer.information.name}}<span class="secondary-text">{{customer.information.phone}}</span> </span> <i class="icon-message item-action"></i></li></ul></div></div>'
})

Related

Insert HTML with AngularJS code inside

any help about who insert html with Angular code inside the html string.
Example:
<div class="container">
<span class='btn' onclick="javascript: clicklink()">click here</span>
<div name="content" id="content">
</div>
</div>
<script>
function clicklink(){
$("#content").html("<span class='label label-danger'>Invoice</span>"+
" <div ng-app ng-init='qty=1;cost=2'> <b>Total:</b> {{qty * cost | currency}} </div>");
}
</script>
Example click here
If you're looking for a 'Hello World' kind of example, this is probably as basic as it gets.
https://code-maven.com/hello-world-with-angular-controller
Maybe the example doesn't make sense, but here is the thing maybe exist another way to do that. I have a project with c# MVC and for render some Views I use ajax
Javascript to load modal into View:
function Edit(){
$.ajax({
url: '../Controller_/Action_',
type: 'POST',
datatype: "html",
traditional: true,
data: { data1: data1 },
success: function (result) {
$('._container').html(result);
},
error: function (result) { }
});
}
MVC c# code:
public ActionResult Edit()
{
...\ code \...
return PartialView("/View/_Edit", model);
}
View Main:
Open Modal
<div name="_container">
<!-- Here load body of modal -->
</div>
Partial view (Edit) return by Action (Edit) in Controller . Should be a modal structure:
<div name="_editModal">
#html.LabelFor( x => x.Name)
#html.EditorFor( x => x.Name)
<div ng-app ng-init="qty=1;cost=2">
<b>Invoice:</b>
<div>
Quantity: <input type="number" min="0" ng-model="qty">
</div>
<div>
Costs: <input type="number" min="0" ng-model="cost">
</div>
<div>
<b>Total:</b> {{qty * cost | currency}}
</div>
</div>
</div>
As already stated by a bunch of people in the comments and other answers this is absolutely bad practice. But there is also a built-in option to solve your problem with pure AngularJS using $compile.
In order to make that work you need to place everything inside a controller or directive and inject the $compile service accordingly.
You need to use the $compile service to produce a function of your dynamic HTML markup which is able to consume a scope object as a parameter in order to produce a working AngularJS template.
After inserting your template, you need to trigger the AngularJS digest cycle using $apply.
<div class="container" ng-controller="MyController">
<span class='btn' ng-click="clicklink()"">click here</span>
<div name="content" id="content">
</div>
</div>
<script>
app.controller("MyController", function($scope, $compile) {
var template = "<button ng-click='doSomething()'>{{label}}</button>";
$scope.clicklink = function(){
$scope.apply(function(){
var content = $compile(template)($scope);
$("#content").append(content);
});
}
});
</script>

Using attributes as text in angular component

I have this little component:
.component('obsbox', {
restrict: 'E',
templateUrl: 'app/components/interactions/html/interactions.obsBox.partial.html',
controller: 'InteractionsController',
controllerAs: 'vm',
bindings: {}
});
All it does it produce a box with some text in it. Nothing spectacular. What I'd like to do is pass a few attributes into the tag and then display those attributes when it resolves.
<obsbox title1="Positive" title2="Experience" score="1"></obsbox>
That should give me a box with "1" in at the top and "Positive Experience" in the bottom. I haven't been able to find anything on SO or anywhere else that explains how I would do that in a way I can understand.
There's nothing in my controller or anywhere else that would be helpful to show you. My controllers are literally doing nothing at the moment.
Any advice?
Edit:
here's the html for the component:
<div layout="row" layout-align="start center" flex="11">
<div layout="column" layout-align="center center" flex="100">
<div layout="row" layout-align="center center" flex="100">
1
</div>
<div layout="row" layout-align="center center" flex="100">
<div layout="column" layout-align="center center" flex="100" style="font-size: x-small">
<div layout="row" layout-align="center center" flex="100">
POSITIVE
</div>
<div layout="row" layout-align="center center" flex="100">
ATTITUDE
</div>
</div>
</div>
</div>
</div>
In my ideal world "1", "Positive", and "Attitude" would come from from attributes on the obsbox tag.
Have you seen the example at https://docs.angularjs.org/guide/component ?
You should fill your bindings like this:
bindings: {
title1:"#",
title2="#",
score="#"
}
# denotes text binding. See the link above for more binding options.
You can then use {{ $ctrl.title1 }} and the other bindings in the template.
For an example, see https://plnkr.co/edit/Gv3TofiO0QyjAOkODjPv?p=info
You can load it into scope using a link function in your directive:
.component('obsbox', {
// the other directive parameters
link: (scope, element, attributes, controller) => {
controller.title1 = attributes.title1;
controller.title2 = attributes.title2;
}
});
The link function is executed once, upon directive compilation.
If you need to update the value, you need to add a watch to that attribute. Angular provides a way to observe attributes with the $observe function:
// in the link function body
attributes.$observe('title1', newValue => {
controller.title1 = newValue;
});
Note that this way, it's using plain strings, not Angular expressions. This means that if you want to have an expression, you would need the $parse service in the directive, or use interpolation at usage site.

AngularJS - HTML losing scope on template replace in ng-repeat

I have the following code in my html.
<div id="section">
<div new-exercise ng-repeat="section in sections track by $index">
</div>
</div>
<div class="add_exercise add_exercise_btn">
<a class="add_exercise_link" ng-click="addExercise()">
<span>+ Add an Exercise</span>
</a>
</div>
the method addExercise() adds a new element to the variable sections, hence updating the html with another template (represented by directive new-exercise).
i.e.
$scope.addExercise = function(){
$scope.sections.push({
title: "hello",
content: "fsa"
});
}
The directive new-exercise:
.directive('newExercise', function () {
return {
templateUrl: '/templates/exercise-form.html',
replace: true,
}
})
The template exercise-form.html:
<div class="add_exercise" id="add_exercise_form" data-section-id="{{id}}">
<form class="new_section">
<div class="input-box">
<input id="title" type="text" name="title" class="form-control" value="{{section.title}}" ng-model="section.title">
<label for="title">Exercise Name</label>
<span class="help-block"></span>
<span>{{ section.title }}</span>
</div>
</form>
</div>
I expect the template exercise-form.html to update the value inside input to be hello but the scope is empty.
However, if I remove the directive and add the template html under ng-repeat it works as I expect. I feel that the scope is lost due to directive, but not so sure about the exact reason. Can anyone explain me the reason and how to resolve?
Thanks.
Remove the replace: true in your directive.
Corrected directive given below:
.directive('newExercise', function () {
return {
templateUrl: '/templates/exercise-form.html'
}
})

Template for directive must have exactly one root element

I am new to angularJs. I am trying to create new directive which contains input element and a button. I want to use this directive to clear input text when button is clicked.
When I use my directive in html I am getting below error :
Error: [$compile:tplrt] Template for directive 'cwClearableInput' must have exactly one root element.
html:
<div class="input-group">
<cw-clearable-input ng-model="attributeName"></cw-clearable-input>
</div>
clearable_input.js:
angular.module('cw-ui').directive('cwClearableInput', function() {
return {
restrict: 'EAC',
require: 'ngModel',
transclude: true,
replace: true,
template: '<input type="text" class="form-control"/><span class="input-group-btn"><button type="button" class="btn" ng-click="" title="Edit"><span class="glyphicon-pencil"></span></button></span>',
controller: function( $scope ) {
}
};
});
I am not able to figure it out how to achieve this.
Well, the error is pretty self-explanatory. Your template needs to have a single root and yours has two. The simplest way to resolve this would be to just wrap the whole thing in a div or a span:
template: '<div><input type="text" class="form-control"/><span class="input-group-btn"><button type="button" class="btn" ng-click="" title="Edit"><span class="glyphicon-pencil"></span></button></span></div>',
Before:
<input type="text" class="form-control"/>
<span class="input-group-btn">
<button type="button" class="btn" ng-click="" title="Edit">
<span class="glyphicon-pencil"></span>
</button>
</span>
After:
<div> <!-- <- one root -->
<input type="text" class="form-control"/>
<span class="input-group-btn">
<button type="button" class="btn" ng-click="" title="Edit">
<span class="glyphicon-pencil"></span>
</button>
</span>
</div>
This error will also occur if the path to the template is incorrect, in which case the error is everything but explanatory.
I was referring the template from within templates/my-parent-template.html with the (incorrect)
template-url="subfolder/my-child-template.html"
I changed this to
template-url="templates/subfolder/my-child-template.html"
which solved it.
Just wrap your template in something:
template: '<div><input type="text" class="form-control"/><span class="input-group-btn"><button type="button" class="btn" ng-click="" title="Edit"><span class="glyphicon-pencil"></span></button></span></div>',
If you don't want to make one root element you can instead set replace to false. In your directive you are setting it to true, which replaces the directive tag "cw-clearable-input" with the root element of your directive.
If you have a comment in your template alongside the root element in the directive template, you will see the same error.
Eg. If your directive template has HTML like this (with "replace" set to true in the directive JS), you will see the same error
<!-- Some Comment -->
<div>
<p>Hello</p>
</div>
So to resolve this in scenarios where you want to retain the comments you will need to move the comment so that it is inside the template root element.
<div>
<!-- Some Comment -->
<p>Hello</p>
</div>
When none of this worked for me, prefixing a / to the template path fixed the issue in my case.
function bsLoginModal() {
return {
restrict: 'A',
templateUrl:'/app/directives/bootstrap-login-modal/template.html',
link: linkFunction,
controller: SignInCtrl,
controllerAs: 'vm'
}
}
instead of
templateUrl:'app/directives/bootstrap-login-modal/template.html
Good Luck.
Check your template or templateUrl
templateUrl: 'some/url/here.html'
template: '<div>HTML directly goes here</div>'
My problem was that webpack's HtmlWebpackPlugin was appending a script tag to the directive content. So angular was seeing:
<div>stuff</div>
<script type="text/javascript" src="directives/my-directive"></script>
The solution is to use HtmlWebpackPlugin's inject option in your webpack.config.js:
new HtmlWebpackPlugin({
template: './src/my-directive.html',
filename: './src/my-directive.html',
inject: false
}),

Angular directive with passed innerHTML containing template code

I am using directives to try to replace some of the often-reoccurring template code that i must write with something simpler.
lets say I have the following original markup:
<!-- section with repeating stuff in it -->
<div some-attributes etc="etc" very-long-tag="true">
<p class="lead">Some description text</p>
<div class="row section short" ng-repeat="row in things">
<div class="col-sm-6 col-md-4" ng-repeat="app in row.col">
<div class="thumbnail">
<img ng-src="im/things/{{app.image}}" alt="..." class="img-circle" width="250">
<div class="caption">
<h3>{{app.name}}</h3>
<p>{{app.desc}}</p>
</div>
</div>
</div>
</div>
</div>
and I want to simplify it by doing something like this:
<!-- section with repeating stuff in it -->
<xx title="Some description text">
<!-- this innerHTML gets passed to the directive -->
<div class="row section short" ng-repeat="row in things">
<div class="col-sm-6 col-md-4" ng-repeat="app in row.col">
<div class="thumbnail">
<img ng-src="im/things/{{app.image}}" alt="..." class="img-circle" width="250">
<div class="caption">
<h3>{{app.name}}</h3>
<p>{{app.desc}}</p>
</div>
</div>
</div>
</div>
<!-- end of innerHTML -->
</xx>
...where there are a several attributes that can be used to shorten the overall block, the directive is currently written this way:
_d.directive('xx', function() {
return {
scope: {
'color': '=',
'option': '=',
'title': '=',
'image': '=',
'image-pos': '=',
'image-size': '='
},
restrict: 'E',
transclude: false,
template: function(element, scope) {
var inside = 'x';
var content = element[0].innerHTML;
var title = scope.title;
var color = scope.color ? 'style="background-color: '+scope.color+'"' : "";
var title = scope.title ? '<h2 class="centertext marginBottom20">'+scope.title+'</h2>' : '';
return ['<div class="section row short" '+color+' ng-transclude>',
title,
content, //this may contain {{template code}}, but it always gets omitted
'</div>'
].join("\n");
},
};
});
The problem is that the existing HTML always gets omitted if it contains any {{angular template code}}.
How do I write the directive so that it still honors the template code?
Ive successfully fixed the issue with the directive, but it took several steps.
Use the correct scope properties. instead of using '=', I used '#'
That was based on the following link: What is the difference between '#' and '=' in directive scope in AngularJS?
The thing to note about scope isolation using #, =, and & affects the way you must refer to the variable in the template. for example, using = means that I would refer the variable without brackets while using # would refer to the variable with {{brackets}}.
Like I mentioned in the first point, after adjusting the scope properties, i needed to go back and refer to the variables in the correct way depending on how the scope was defined.
ng-transclude when used with {...transclude: true,...} requires that I actually put a container somewhere in the template for that transcluded content. Here's an example of that:
return ['<div class="section row short" '+color+' ng-transclude>',
title,
'<div ng-transclude>', //this is the container for the original innerHTML, transcluded
content, //this may contain {{template code}}, and gets transcluded
'</div>
'</div>'
].join("\n");
Only then did the directive work as expected. Also, props to #rob for providing me with this introductory link, https://egghead.io/lessons/angularjs-components-and-containers.

Categories