$templateCache to fancybox, how to bind variables to controller scope - angularjs

I have been struggling for a coupe of hours trying to get fancybox to display html template from $templateCache. It all works fine except for the annoying fact the the data binding does not work and I'm not sure how to solve it.
<div ng-controller="MyCtrl">
Hello, {{ templateVariable }}!
<script type="text/ng-template" id="testTemplate.html">
<h1>{{ templateVariable }}</h1>
<p>Bla bla bla</p>
</script>
<br /><br />
<a href="#" show-template>Show template</a>
</div>
var myApp = angular.module('myApp',[]);
myApp.directive('showTemplate', function($templateCache, $compile, $parse) {
return {
restrict: 'A',
link: function (scope, element, attrs, ctrl) {
element.bind('click', function() {
var template = $templateCache.get('testTemplate.html');
var compiled = $compile(template)(scope);
$.fancybox.open(template);
});
}
};
});
myApp.controller('MyCtrl', function($scope) {
$scope.templateVariable = 'My template variable';
});
JSFiddle:
http://jsfiddle.net/oligustafsson/p4f7mh19/
Anyone have any insights to how to accomplish this feat?

To answer my own question, this is what I came up with:
<div ng-controller="MyCtrl">
Hello, {{ templateVariable }}!
<script type="text/ng-template" id="testTemplate.html">
<div>
<h1>{{ templateVariable }}</h1>
<p>Bla bla bla</p>
<div>Mooo</div>
</div>
</script>
<br /><br />
Show template
</div>
I wrapped the template html in a div.
var myApp = angular.module('myApp',[]);
myApp.directive('showTemplate', function($templateCache, $compile, $timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs, ctrl) {
element.bind('click', function() {
$timeout( function(){
var template = $templateCache.get('testTemplate.html');
var linkFn = $compile(template);
var linkedContent = linkFn(scope);
$.fancybox.open(linkedContent);
}, 0)
});
}
};
});
myApp.controller('MyCtrl', function($scope) {
$scope.templateVariable = 'My template variable';
});
Finding some other suggestions like using $timeout and $compile, this seems to work just fine.
JSFiddle: http://jsfiddle.net/oligustafsson/vpbutty0/
Thanx!

Related

Angularjs - Scope value is not applied in template

I have used the directive scope in directive template.
I have tried to get the html from template cache which was stored earlier.
But the current directive scope is not applied to the directive. I don't what will be the reason.
I have tried to compile the template and get the value. But not applied.
contentString = $templateCache.get('template/MyTemplate')
var div = document.createElement("div");
div = angular.element(div).html(contentString);
var s = $compile(div.contents())($scope);
template/MyTemplate would be following
<div>
{{obj.value}}
</div>
Directive scope like following,
link: function ($scope, $element, $attributes) {
$scope.obj.value="This is my test"
}
I got the output like
<div class="ng-scope">
{{obj.value}}
</div>
What will be the issue?
Check this example which is using a custom directive with an isolated scope. I hope the below examples will be of help to you.
angular
.module('demo', [])
.directive('hello', hello);
hello.$inject = ['$templateCache', '$compile'];
function hello($templateCache, $compile) {
var directive = {
scope: {
},
link: linkFunc
};
return directive;
function linkFunc(scope, element, attrs, ngModelCtrl) {
scope.obj = {
value: 'Hello, World!'
};
var template = $templateCache.get('templateId.html');
element.html(template);
$compile(element.contents())(scope);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="demo">
<hello></hello>
<script type="text/ng-template" id="templateId.html">
<div>
{{obj.value}}
</div>
</script>
</div>
Another example using controller aliasing syntax i.e. controller as with a directive to be consistent with using controller as with view and controller pairings
angular
.module('demo', [])
.controller('DefaultController', DefaultController)
.directive('hello', hello);
function DefaultController() {
var vm = this;
vm.message = 'Hello, World!';
}
hello.$inject = ['$templateCache', '$compile'];
function hello($templateCache, $compile) {
var directive = {
link: linkFunc,
scope: {
message: '='
},
controller: HelloController,
controllerAs: 'vm',
bindToController: true
};
return directive;
function linkFunc(scope, element, attrs, ngModelCtrl) {
var template = $templateCache.get('templateId.html');
element.html(template);
$compile(element.contents())(scope);
}
}
function HelloController() {
var vm = this;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<hello message="ctrl.message"></hello>
<script type="text/ng-template" id="templateId.html">
<p>{{vm.message}}</p>
</script>
</div>
</div>

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

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>

how to test Bootstrap Modal in AngularJS using jasmine?

I am using bootstrap modal for displaying pop up's in angular app. It is working perfectly from front end but DOM elements inside pop up are not getting appended to the body
In the output, when I am displaying content of document, content of my html template is not getting appended to body tag. So I am unable to find/test any DOM element. It is not displaying any errors in console also.
Please any one can help me in resolving this issue by specifying how to test bootstrap modal in angular application using karma/jasmine.
angular.module("myApp").directive('popUp', ['$http', '$compile', function($http, $compile) {
return {
restrict: 'A',
replace: true,
scope: {
course: '=',
},
compile: function(element, cAtts){
var template,
$element,
loader;
var windowOpen = false;
loader = $http.get('components/popUp.view.html').success(function(data) {
template = data;
});
//return the Link function
return function(scope, element, lAtts) {
element.on('click', function(e) {
e.preventDefault();
$element = $( $compile(template)(scope) );
$element.modal({backdrop: 'static'});
windowOpen = true;
});
// if the template changes, we need to compile the current
// template again. just in case there are funky sticky things
scope.$watch('template', function(newValue, oldValue) {
if(newValue == undefined && oldValue == undefined) return;
if(windowOpen) return;
if(newValue == undefined){
//$(".modal").remove();
$element.remove();
$element = undefined;
return;
}
$element = $( $compile(template)(scope) );
});
};
}
}
}]);
My HTML Template:
<div id="{{handler}}" class="modal fade">
<div style="margin:-1px auto; width:90%;float:right;" class="modal-dialog">
<div style="padding-left: 25px; height:100vh;" class="modal-content">
<div class="modal-header navbar-static-top"><img src="content/assets/img/close.png" data-dismiss="modal" aria-hidden="true" ng-click="close()" title="Close" alt="Close" class="popUpClose close pull-left"/>
<div class="popUpTitle">
<div style="font-size:22px;">{{course.CourseName}}</div>
<div style="font-size:15px; margin-top:-5px;">{{course.CourseId}}</div><br/>
</div>
</div>
<div style="display:inline" class="modal-body">
<p>This is test Modal</p>
</div>
<div style="border:none;" class="modal-footer"> </div>
</div>
</div>
</div>
My Test File:
(function(){
"use strict";
describe("Testing Pop Up Directive Functionality", function(){
var $httpBackend, $scope, fakeData, $compile, $document;
var compileDirective, course, element, template;
beforeEach(module('myApp.testing'));
beforeEach(module('myApp'));
beforeEach(inject(function ($injector, _$templateCache_, _$httpBackend_, _fakeData_, _$document_) {
$httpBackend = _$httpBackend_;
fakeData = _fakeData_;
$document = _$document_;
angular.module('components/popUp.view.html')._runBlocks[0](_$templateCache_);
template = _$templateCache_.get('components/courses/course.attendance.popUp.view.html');
course = fakeData.fakeCourses.Courses[0];
compileDirective = function() {
inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$scope = _$rootScope_.$new();
$scope.course=course;
element = angular.element('<div manageattendance="" course="course"></div>');
element = $compile(element)($scope);
});
//$scope.$digest();
};
}));
it("Should display attendance of course if user is authorized", function(){
$httpBackend.expectGET('components/courses/course.attendance.popUp.view.html').respond(template);
compileDirective();
$httpBackend.flush();
element.trigger('click');
console.log($document.find('html').html());
});
});
})();
AngularJS : 1.3.11
Bootstrap : 3.3.2
Karma : 0.12.31
Jasmine-core : 2.3.4
karma-jasmine : 0.3.5
I am not sure what is the cause but by removing css class "fade" from modal div, html content from modal is getting appended to the body tag.

Compile a dynamic directive inside a template

I have a directive like this:
foldeskApp.directive('contributionFooter', function() {
return {
restrict: 'C',
template: '<button type="button" class="btn" ng-class="{\'btn-success\': canCreate()}">Add</button>'
};
});
And a controller like this:
foldeskApp.controller('MainCtrl',
['Auth', '$scope', function(Auth, $scope) {
$scope.footerType = 'contribution';
}]);
Can I call the directive like this?
<div class="modal-footer {{footerType}}-footer"></div>
You need to compile the DOM using the $compile service.
Here's an example of how to achieve that, although I'm not a fan of using $timeout here:
http://codepen.io/jlowcs/pen/jEKKjZ
HTML:
<div ng-controller="MainCtrl">
<div class="modal-footer {{footerType}}-footer"></div>
</div>
JS:
angular.module('exampleApp', [])
.directive('contributionFooter', function() {
return {
restrict: 'C',
template: '<button type="button" class="btn" ng-class="{\'btn-success\': canCreate()}">Add</button>'
};
})
.controller('MainCtrl', function($scope, $element, $timeout, $compile) {
$scope.footerType = 'contribution';
//timeout to do it when {{footerType}} has been replaced
//but it would probably be best to do this in a link function in a directive
$timeout(function () {
$compile($element.children())($scope);
});
});
angular.bootstrap(document, ['exampleApp']);

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 :-)

Resources