Variable value not passing in a controller using directive with ng-class - angularjs

I am referencing the value of the variable in a controller in an ng-class template but its not working.
here is the html directive template URl :
<div class="tooltip-anchor">
<div class=" tooltip-content ehub-body" ng-class="{ 'tooltip__content--disabled': tooltipContentValue}" ng-transclude>Tooltip content</div>
</div>
Here is where i am using the directive in the index page
<div style="text-align:center;">
<ehub-tooltip>Hello i am here, and i am her to stay</ehub-tooltip>over here
<ehub-tooltip>Be nice to people on your way up and they will be nice to you on your way down</ehub-tooltip>click me
</div>
And here is the directive:
in this directive i am creating a variable and setting it to false and also trying to use it in an ng-class attribute
(function (window) {
'use strict';
angular
.module('ehub.component.tooltip', [])
.controller('ehubTooltipCtrl', ['$scope', function ($scope) {
$scope.tooltipContentValue = false;
}])
.directive('ehubTooltip', ehubTooltip);
function ehubTooltip() {
var directive = {
controller: "ehubTooltipCtrl",
link: link,
transclude: true,
templateUrl: 'ehub-tooltip.html',
restrict: 'E'
};
return directive;
function link(scope, element, attrs) {
scope.keyupevt = function () {
if (event.keyCode === 27) {
$scope.tooltipContentValue = true;
}
}
}
}
})();

Try this working jsfiddle.
angular.module('ExampleApp', ['ngMessages'])
.controller('ExampleController', function($scope) {
})
.directive('ehubTooltip', function() {
var directive = {
link: link,
transclude: true,
template: '<div class="tooltip-anchor"><div class=" tooltip-content ehub-body" ng-class="{ \'tooltip__content--disabled\': tooltipContentValue}" ng-transclude>Tooltip content</div></div>',
restrict: 'E'
};
function link(scope, element, attrs) {
scope.tooltipContentValue = false;
scope.keyupevt = function() {
if (event.keyCode === 27) {
scope.tooltipContentValue = true;
}
}
}
return directive;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<div style="text-align:center;">
<a href="" ng-keyup="keyupevt()">
<ehub-tooltip>Hello i am here, and i am her to stay</ehub-tooltip>over here</a>
<a href="" ng-keyup="keyupevt()">
<ehub-tooltip>Be nice to people on your way up and they will be nice to you on your way down</ehub-tooltip>click me</a>
</div>
</div>
</div>

Related

angular bind html tags from controller to html view

I need to render the $scope.htmlView tags in to html view.
I already tried using ng-bind-html. It renders the html tags but scope variable values will not appear.
How can I render both html tags and and scope variable values?
This is the controller:
$scope.newObj = {
billStatus : true;
eventTime : "2015-01-10"
};
$scope.htmlView = '<p>{{newObj.eventTime}}</p> <div style="margin-top: -15px;"><md-checkbox ng-checked="{{newObj.billStatus}}" style="margin-left: 0px;" aria-label="Bilable"><span style="margin-left:0px;">Bilable</span> </md-checkbox></div>'
Expected result is:
<p> 2015-01-10</p>
<div style="margin-top: -15px;">
<md-checkbox ng-checked="true" style="margin-left: 0px;" aria- label="Bilable">
<span style="margin-left:0px;">Bilable</span>
</md-checkbox>
</div>
I search over the internet over days and still could't find out a way to figure out this. please help me. thank you.
You have to do 2 things.
Use data-ng-bind-html=""
Use $sce.trustAsHtml(string)
UPDATED:
If you wont to use angular expressions, you have to compile them using
$compile.
You can read more via this $SCE
I will tell you a long way but it will help you.Make a custom directive like this.
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
Use as
<span dynamic="{{htmlView}}" >
Hi please check this fiddle
https://plnkr.co/edit/iqNltdDYv2n9Agke0C2C?p=preview
HTML
<div ng-controller="ExampleController">
<p >{{newObj.eventTime}}</p>
<p dynamic="htmlView"></p>
</div
and JS
(function(angular) {
'use strict';
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.newObj = {
billStatus : true,
eventTime : "2015-01-10"
}
$scope.htmlView = '<p> {{newObj.eventTime}}</p> <div style="margin-top: -15px;">Hello <md-checkbox ng-checked="{{newObj.billStatus}}" style="margin-left: 0px;" aria-label="Bilable"><span style="margin-left:0px;">Bilable</span> </md-checkbox></div>'
}])
.directive('dynamic', function($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, element, attrs) {
scope.$watch(attrs.dynamic, function(html) {
element[0].innerHTML = html;
$compile(element.contents())(scope);
});
}
};
});
})(window.angular);

Angular directive scope - template include vs inline transclude

I have an angular directive for displaying a modal window. It can accept the contents either inline between the HTML tags, or be pointed to a template. When using this directive I seem to have normal access to the $scope when I am using the transcluded inline version of this directive, but when I use a template I do not.
What am I missing here? I've made a smaller sample directive that has the same behavior.
Demo: http://fiddle.jshell.net/ahezfaxj/2
Inline Content Usage
<ang-test show="showBoolean">
<p>Content here!</p>
</ang-test>
Template Usage
<ang-test show="showBoolean" template="'myTemplate.html'"></ang-test>
Directive
app.directive("angTest", function () {
return {
template: function () {
return "<div class='test-container'>" +
" <div ng-if='show && template' ng-include='template'></div>" +
" <div ng-if='show && !template' ng-transclude></div>" +
"</div>";
},
restrict: "E",
replace: true,
transclude: true,
scope: {
template: "#",
show: "="
},
link: function ($scope, $element, attrs) {
if(value){
$element[0].style.display="block";
}else{
$element[0].style.display="none";
}
}
};
});
Please see demo below. You created isolated scope in your directive thus your directive scope is not this same as controller $scope. But you can add as well thing to your directive scope like in example below.
I hope that will help.
var app = angular.module("app", []);
app.controller("BaseCtrl", function ($scope) {
$scope.thing = "Hello!";
$scope.showOne=false;
$scope.showTwo=false;
});
app.directive("angTest", function () {
return {
template: function () {
return "<div class='test-container'>" +
" <div ng-if='show && template' ng-include='template'></div>" +
" <div ng-if='show && !template' ng-transclude></div>" +
"</div>";
},
restrict: "E",
replace: true,
transclude: true,
scope: {
template: "#",
show: "=",
thing:'#'
},
link: function ($scope, $element, attrs) {
//Show/hide when `show` changes
$scope.$watch("show", function (value) {
if(value){
$element[0].style.display="block";
}else{
$element[0].style.display="none";
}
});
}
};
});
.test-container{
padding:5px;
background: #EEE;
}
.transcluded {
color:red
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="BaseCtrl">
Outside Directive: <strong>{{thing}}</strong>
<hr />
<button type="button" ng-click="showOne=!showOne">Toggle One</button>
<ang-test show="showOne">
<p class="transcluded">Inside Included Directive: <strong>--> thing transcluded-->{{thing}}</strong></p>
</ang-test>
<hr />
<script type="text/ng-template" id="myTemplate">
<p>Inside Template Directive: <strong>thing from directive scope -->{{thing}}</strong></p>
</script>
<button type="button" ng-click="showTwo=!showTwo" >Toggle Two</button>
<ang-test show="showTwo" template="myTemplate" thing="{{thing}}"></ang-test>
</div>
</div>

Angularjs Directive finding element inside ngIf

I have created a angularjs directive that are supposed to display an address.
$(elem).find('button').length
now return the correct value but it have been called a hack and is there a better way to do it. I understand that ngIf creates a child scope and the button element isn't available when my link code runs if I don't wrap it in $timeout.
So what is the pretty way to access the element inside my ngIf without the $timeout hack?
My Directive
angular.module('directives')
.directive('addresss', ['$timeout', function ($timeout) {
return {
restrict: 'AE',
scope: {
address: '='
},
templateUrl: 'template........ ',
link: function(scope,elem,attr){
$timeout(function(){
console.log($(elem).find('button').length);
})
}
};
}]);
Template for address directive
<div class="spacer">
<h1>Address</h1>
<div>
<strong>{{address.name}}</strong>
</div>
<div ng-if="address.name">
<button class="btn-link">Delete</button>
</div>
</div>
if all you want to bind a click event you could just put a ng-click in the button:
JS:
app.directive('address', [function () {
return {
restrict: 'AE',
scope: {
address: '='
},
templateUrl: 'template.html ',
link: function(scope,elem,attr){
scope.myClickHandler = function() {
console.log('button clicked');
});
}
};
Template:
<div class="spacer">
<h1>Address</h1>
<div>
<strong>{{address.name}}</strong>
</div>
<div ng-if="address.name">
<button ng-click="myClickHandler()" class="btn-link">Delete</button>
</div>
</div>
Try this (if I get well your question)
html
<div data-ng-controller="MainController">
<div data-my-dir address="address"></div>
</div>
js
angular.module('myApp', [])
.controller('MainController',function($scope) {
$scope.address = {
name : 'myname'
};
})
.directive("myDir", function () {
return {
scope:{
address: '=',
},
template:'<button class="btn-link" ng-if="address.name">Delete</button>',
link: function (scope, elem) {
console.log(scope.address.name);
}
}
});

Angular placing functions

I'm using the angular-google-maps library in my project. I have used a directive to load a custom google maps menu. The goal is to obviously reuse the directive. In the menu are a couple of buttons which when clicked should all carry out a function. I'm still trying to get my head around on how to do that, so here is my problem:
I would like to pan the map to its original position when the button "Home" is clicked. Normally that is just done with ng-click and the function is placed within the scope of the controller. With the directive I'm confused. Where should I place the "home()" function? Directive? Directive controller? Controller? I hope this makes any sense?!?!
HTML:
<div class="map_canvas">
<google-map center="map.center" zoom="map.zoom" draggable="true">
<marker ng-repeat="m in map.markers" coords="m" icon="m.icon" click="onMarkerClicked(m)">
<marker-label content="m.name" anchor="50 0" class="marker-labels"/>
<window ng-cloak coords="map.center" isIconVisibleOnClick="false" options="map.infowindows.options">
<p>This is an info window at {{ m.latitude | number:4 }}, {{ m.longitude | number:4 }}!</p>
<p class="muted">My marker will stay open when the window is popped up!</p>
</window>
</marker>
<map-custom-control position="google.maps.ControlPosition.TOP_CENTER" control-template="../templates/gmaps/main_menu.html" control-click=""></map-custom-control>
</google-map>
</div>
Template:
<div class="gmaps-menu">
<div class="gmaps-row">
<button type="button" class="btn btn-default"><img class="glyphicon-custom" src="../img/icons/glyphicons/glyphicons_020_home.png" ng-click="home()"></button>
<button type="button" class="btn btn-default"><img class="glyphicon-custom" src="../img/icons/glyphicons/glyphicons_349_fullscreen.png"></button>
<button type="button" class="btn btn-default"><img class="glyphicon-custom" src="../img/icons/glyphicons/glyphicons_096_vector_path_polygon.png"></button>
<button type="button" class="btn btn-default"><img class="glyphicon-custom" src="../img/icons/glyphicons/glyphicons_030_pencil.png"></button>
</div>
</div>
Directive:
AppDirectives.directive('mapCustomControl', ['$log', '$timeout', '$http', '$templateCache', 'google', 'GMapsLib' ,function ($log, $timeout, $http, $templateCache, google,GMapsLib) {
return {
restrict: 'E',
replace: true,
require: '^googleMap',
link: function(scope,element,attr,mapCtrl){
if (!angular.isDefined(attr.controlTemplate)) {
$log.error('map-custom-control: could not find a valid control-template property!');
return;
}
var templateUrl = attr.controlTemplate;
var position = google.maps.ControlPosition.TOP_CENTER;
if (angular.isDefined(attr.position)) {
var EVAL_IS_OK_WE_CONTROL_THE_INPUT = eval;
position = EVAL_IS_OK_WE_CONTROL_THE_INPUT(attr.position);
}
$timeout(function() {
var map = mapCtrl.getMap();
var controlDiv = document.createElement('div');
controlDiv.style.padding = '5px';
controlDiv.style.width = 'auto';
controlDiv.marginLeft = 'auto';
controlDiv.marginRight = 'auto';
$http.get(templateUrl, {cache: $templateCache})
.success(function(html) {
controlDiv.innerHTML = html;
})
.then(function (/*response*/) {
map.controls[position].push(controlDiv);
if (angular.isDefined(attr.controlClick)) {
google.maps.event.addDomListener(controlDiv, 'click', function() {
scope.$apply(attr.controlClick);
});
}
}
);
});
}
};
}]);
You can pass the scope function that has to be executed on the controller:
HTML
<div ng-app="app" ng-controller="sampleCtrl">
<maps-custom-control click-handler="alertMe()"></maps-custom-control>
</div>
JS
var app = angular.module('app', []);
app.directive('mapsCustomControl', function() {
return {
restrict: 'EA',
replace: true,
scope: {
clickHandler: '&'
},
template: '<div style="width: 100px; height:100px; background-color: red;" ng-click="clickHandler()"></div>'
};
});
app.controller('sampleCtrl', function ($scope) {
$scope.alertMe = function () {
window.alert('Refresh gMaps control');
};
});
Since we pass the alertMe function, this is the function that will get executed, I hope this makes sense?
Fiddle
A small remark on your code, it would be better if you get the template as follows:
app.directive('..', function() {
return {
template: '<div ng-include="getTemplate()"></div>',
link: function(scope, element, attr) {
scope.getTemplate = function() {
return this.attr.controlTemplate;
}
}
};
});
This way you don't need to do any strange ajax calls. Just add all the mark-up in your template and include it. don't make it necessary hard :-)

Angular.js directive dynamic templateURL

I have a custom tag in a routeProvider template that that calls for a directive template. The version attribute will be populated by the scope which then calls for the right template.
<hymn ver="before-{{ week }}-{{ day }}"></hymn>
There are multiple versions of the hymn based on what week and day it is. I was anticipating to use the directive to populate the correct .html portion. The variable is not being read by the templateUrl.
emanuel.directive('hymn', function() {
var contentUrl;
return {
restrict: 'E',
link: function(scope, element, attrs) {
// concatenating the directory to the ver attr to select the correct excerpt for the day
contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
},
// passing in contentUrl variable
templateUrl: contentUrl
}
});
There are multiple files in excerpts directory that are labeled before-1-monday.html, before-2-tuesday.html, …
emanuel.directive('hymn', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
// some ode
},
templateUrl: function(elem,attrs) {
return attrs.templateUrl || 'some/path/default.html'
}
}
});
So you can provide templateUrl via markup
<hymn template-url="contentUrl"><hymn>
Now you just take a care that property contentUrl populates with dynamically generated path.
You can use ng-include directive.
Try something like this:
emanuel.directive('hymn', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
scope.getContentUrl = function() {
return 'content/excerpts/hymn-' + attrs.ver + '.html';
}
},
template: '<div ng-include="getContentUrl()"></div>'
}
});
UPD. for watching ver attribute
emanuel.directive('hymn', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
scope.contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
attrs.$observe("ver",function(v){
scope.contentUrl = 'content/excerpts/hymn-' + v + '.html';
});
},
template: '<div ng-include="contentUrl"></div>'
}
});
Thanks to #pgregory, I could resolve my problem using this directive for inline editing
.directive("superEdit", function($compile){
return{
link: function(scope, element, attrs){
var colName = attrs["superEdit"];
alert(colName);
scope.getContentUrl = function() {
if (colName == 'Something') {
return 'app/correction/templates/lov-edit.html';
}else {
return 'app/correction/templates/simple-edit.html';
}
}
var template = '<div ng-include="getContentUrl()"></div>';
var linkFn = $compile(template);
var content = linkFn(scope);
element.append(content);
}
}
})
You don't need custom directive here. Just use ng-include src attribute. It's compiled so you can put code inside. See plunker with solution for your issue.
<div ng-repeat="week in [1,2]">
<div ng-repeat="day in ['monday', 'tuesday']">
<ng-include src="'content/before-'+ week + '-' + day + '.html'"></ng-include>
</div>
</div>
I had the same problem and I solved in a slightly different way from the others.
I am using angular 1.4.4.
In my case, I have a shell template that creates a CSS Bootstrap panel:
<div class="class-container panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">{{title}} </h3>
</div>
<div class="panel-body">
<sp-panel-body panelbodytpl="{{panelbodytpl}}"></sp-panel-body>
</div>
</div>
I want to include panel body templates depending on the route.
angular.module('MyApp')
.directive('spPanelBody', ['$compile', function($compile){
return {
restrict : 'E',
scope : true,
link: function (scope, element, attrs) {
scope.data = angular.fromJson(scope.data);
element.append($compile('<ng-include src="\'' + scope.panelbodytpl + '\'"></ng-include>')(scope));
}
}
}]);
I then have the following template included when the route is #/students:
<div class="students-wrapper">
<div ng-controller="StudentsIndexController as studentCtrl" class="row">
<div ng-repeat="student in studentCtrl.students" class="col-sm-6 col-md-4 col-lg-3">
<sp-panel
title="{{student.firstName}} {{student.middleName}} {{student.lastName}}"
panelbodytpl="{{'/student/panel-body.html'}}"
data="{{student}}"
></sp-panel>
</div>
</div>
</div>
The panel-body.html template as follows:
Date of Birth: {{data.dob * 1000 | date : 'dd MMM yyyy'}}
Sample data in the case someone wants to have a go:
var student = {
'id' : 1,
'firstName' : 'John',
'middleName' : '',
'lastName' : 'Smith',
'dob' : 1130799600,
'current-class' : 5
}
I have an example about this.
<!DOCTYPE html>
<html ng-app="app">
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container-fluid body-content" ng-controller="formView">
<div class="row">
<div class="col-md-12">
<h4>Register Form</h4>
<form class="form-horizontal" ng-submit="" name="f" novalidate>
<div ng-repeat="item in elements" class="form-group">
<label>{{item.Label}}</label>
<element type="{{item.Type}}" model="item"></element>
</div>
<input ng-show="f.$valid" type="submit" id="submit" value="Submit" class="" />
</form>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
angular.module('app', [])
.controller('formView', function ($scope) {
$scope.elements = [{
"Id":1,
"Type":"textbox",
"FormId":24,
"Label":"Name",
"PlaceHolder":"Place Holder Text",
"Max":20,
"Required":false,
"Options":null,
"SelectedOption":null
},
{
"Id":2,
"Type":"textarea",
"FormId":24,
"Label":"AD2",
"PlaceHolder":"Place Holder Text",
"Max":20,
"Required":true,
"Options":null,
"SelectedOption":null
}];
})
.directive('element', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
scope.contentUrl = attrs.type + '.html';
attrs.$observe("ver", function (v) {
scope.contentUrl = v + '.html';
});
},
template: '<div ng-include="contentUrl"></div>'
}
})

Resources