Dynamically add a directive in AngularJS within Gridster - javascript

I just started working with AngularJS but I found a small problem that I cant find out, I hope you peeps can help me.
I have imported AngularJS Gridster, a simple way to add a dynamic grid to your webpage. Now everything works and the element get succesfully loaded from the database and imported in Gridster but now I want to do the following thing. In the JSON that is retrieved from the database there is also an attribute called "directive". Now, when everything is loaded I want to add in each Gridster element the directive that is returned from the database.
<ul>
<li gridster-item="item" ng-repeat="item in gridsterItems">
{{ item.directive }} // Returns <clock-widget></clock-widget> and print it to the screen, but it dont run the directive and doesn't display.
</li>
</ul>
Now it returns the right value and display the string on the screen but I want to run it directive clockWidget.
app.directive('clockWidget', function() {
return {
replace: true,
template: 'Yups, I am the clockwidget',
};
});
On the internet I read something about $compile but I can't find out. I hope you peeps can help me.
Thanks!

Yes, you need use $compile. See documentation.
Live example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope) {
$scope.directives = ["<directive-one></directive-one>", "<directive-two val='inputVal'></directive-two>"];
})
.directive('compileDirective', function($compile) {
return {
restrict: "E",
replace: true,
link: function(scope, element, attr) {
scope.$watch(function() {
return attr.directive;
}, function(val) {
element.html("");
if (val) {
var directive = $compile(angular.element(val))(scope);
element.append(directive);
}
});
}
};
})
//Directives for example
.directive('directiveOne', function($compile) {
return {
replace: true,
template: "<div>i'm directive one</div>"
};
})
.directive('directiveTwo', function($compile) {
return {
replace: true,
scope:{val:"="},
template: "<div>i'm directive two with val={{val}}</div>"
};
})
.directive('directiveThree', function($compile) {
return {
replace: true,
scope:{val:"="},
template: "<div>i'm directive three</div>"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<select ng-model="selectDirective" ng-options="dir for dir in directives">
</select>
<input ng-model="inputVal">
<compile-directive directive="{{selectDirective}}"></compile-directive>
<compile-directive directive="<directive-three></directive-three>"></compile-directive>
</div>
</div>

Related

Angular custom directive calling another custom directive

I am developing an angular framework where user can configure header, menu, footer and selected pages using custom directives. To complete this requirement, at one point I need the following. I have seen example on the net, but does not really explain it well.
The requirement is that the templateUrl of the first custom directive shall be replaced with a template attribute that should call another custom directive.
The following code with templateUrl works fine.
angular.module("app",[]);
angular.module("app").controller("productController", ['$scope', function ($scope) {
}]);
angular.module("app").directive("tmHtml", function () {
return {
transclude: false,
scope: {
},
controller: "productController",
templateUrl: "/templates/HideShow.html"
};
});
However, when I change the above code as follows. I am making the change so that my custom directive tmHtml calls another custom directive.
angular.module("app").directive("tmHtml", function () {
return {
transclude: false,
scope: {
},
controller: "productController",
template: ``<hideShow></hideShow>``
};
});
New Directive for hideShow is written as follows
angular.module("app").directive("hideShow", function () {
return {
tempateUrl: "/templates/HideShow.html"
};
});
It's not working. I understand I am missing something here. I could not find out. Appreciate help
Working code:
var app = angular.module('plunker', []);
app.controller('productController', function($scope) {
});
app.directive("hideShow", function() {
return {
templateUrl: "hideshow.html"
};
});
app.directive("tmHtml", function() {
return {
transclude: false,
scope: {},
controller: "productController",
template: "<hide-show></hide-show>"
};
});
the problem is with the spelling of templateUrl in your hideShow directive.
Demo : http://plnkr.co/edit/TaznOeNQ7dM9lyFgqwCL?p=preview
Try define your controller with controllerAs:
angular.module("app").directive("tmHtml", function () {
return {
transclude: false,
scope: {
},
controllerAs: "productController",
templateUrl: "/templates/HideShow.html"
};
});
angular.module("app").directive("tmHtml", function () {
return {
transclude: false,
scope: {
},
controller: "productController",
template: ``<hideShow></hideShow>``
};
});
must be replaced by
angular.module("app").directive("tmHtml", function () {
return {
transclude: false,
scope: {
},
controller: "productController",
template: "<hide-show></hide-show>"
};
});
under the attribute template, you add Html. So, you still have to use snake-case there, like in your Html files
Your first directive may have an eventually scoped attribute that you observe.
Then it may wrap the second directive. If needed, your directives may communicates as parents and children.

How to pass a variable from a directive (ngModel) into the html outside of the directive

I've got a custom directive with an html template and it basically is a menu option. When a user makes a selection it updates the ng-model variable within the directive.
But I would like for the ng-model variable within the directive passed outside of the directive into the html page.
Here's the code snippets:
Directive:
(function() {
'use strict';
angular
.module('myModule')
.controller('myController', ['$scope', function($scope) {
$scope.sortByOptions = [
{ value:'red', displayText:'Redder' },
{ value:'blue', displayText:'Bluer' },
{ value:'gold', displayText:'Golder' },
{ value:'brown', displayText:'Browner' }
];
}]
)
.directive('myDirective', myDirective);
myDirective.$inject = [];
function myDirective() {
return {
restrict: 'A',
templateUrl: 'mydirective/sorting.html',
}
}
})();
HTML Template for the directive:
<select ng-model="sortBy" ng-options="sortByOption.displayText for sortByOption in sortByOptions track by sortByOption.value"> </select> {{sortBy.value}}
HTML of the Page:
<div class="col-md-8 form-inline" my-directive>
</div>
<!-- need ng-model variable from my-directive passed into sortBy --> <!-- it's being called on same page. I turned a menu options into a directive to save from copying/pasting same code everywhere. when the menu option gets selected it populates a list which is the li you see below -->
<li ng-repeat="object in objects | filter: searchTool | orderBy: (sortAscending ? '' : '-') + sortBy">
<div class="plank">
<div class="plank-header">
</div>
</div>
</li>
As you can see I'm trying to pass ng-model="sortBy" value from the directive which is chosen by the user into other parts of the page called sortBy that is within the li.
It would be awesome if someone can give an example of what they did.
I've done something similar by essentially exposing the variable in your directive to your controller. You can do this by passing a function from your controller into your directive such that that function gets called and essentially sets a variable in your controller. Something like this.
<div mydirective call-outside-function="setSortBy".....>
mycontroller function(...) {
$scope.setSortBy = function(sb) {
$scope.localSortBy = sb;
};
}
mydirective .....
link: function(scope,element,attrs) {
scope.$watch('sortBy',function(newval) {
attrs.callOutsideFunction(newval);
});
}
Probably not the most elegant solution but it works
I did the following:
1) added a scope.$watch to allow my directive to listen for a change in that variable on the DOM. Then it will set the new value in the controller
2) Added the controller into the directive. I originally forgot to add a line in the function colorSorter to return the controller
3) I did not need to modify the directive's html template or the main html template for the page to get it working.
Here is the directive:
(function() {
angular
.module('myModule')
.controller('sortController', ['$scope', function($scope) {
$scope.sortByOptions = [
{ value:'red', text:'Redder' },
{ value:'blue', text:'Bluer' },
];
$scope.sortBy = {value: undefined}
}]
)
.directive('colorSorter', colorSorter);
colorSorter.$inject = [];
function colorSorter() {
return {
restrict: 'A',
templateUrl: 'app/color-sorter/color-sorter.html',
controller: 'sortByController',
link: function (scope) {
scope.$watch('sortBy.value', function (value) {
console.log(value);
})
}
}
}
})();

Is it possible to dynamically load directives in a template?

I'm making a widget system and I plan to have each widget be it's own directive. I want to be able to pass the directives that should be used from my controller to my view via an array.
This is what my code currently looks like:
app.controller('showDashboard', function ($scope){
$scope.widgets = ['widget1', 'widget2', 'widget3'];
});
In View:
<article ng-repeat="widget in widgets" class="widget">
<div {{widget}}></div>
</article>
Directive:
app.directive('widget1', function (){
return {
restrict: "A",
templateUrl: 'testWidget.html'
};
}).directive('widget2', function (){
return {
restrict: "A",
templateUrl: 'testWidget.html'
};
}).directive('widget3', function (){
return {
restrict: "A",
templateUrl: 'testWidget.html'
};
});
So rather than make the directive itself the widget, why not use ng-include to load in the templates which can themselves contain directives, controllers etc...
app.controller('showDashboard', function ($scope){
$scope.widgets = ['widget1.html', 'widget2.html', 'widget3.html'];
});
<article ng-repeat="widget in widgets" class="widget">
<div ng-include="widget"></div>
</article>
Here is a jsFiddle with an example.
And here is an updated fiddle that shows a slightly more complex widget with a controller.
It can be improved but just to get the idea
//html
<div wrapper mydir="widget"></div>
//js
.directive('wrapper', function ($compile){
return {
restrict: "A",
scope: {
mydir: "="
},
link: function ( scope, element ) {
var html = '<test '+scope.mydir+'></test>';
var compiled = $compile( html )( scope );
element.append(compiled);
}
}
})

Any way to dynamically load angular directives?

Here's a short fiddle:
http://jsfiddle.net/aSg9D/
Basically, neither <div data-foo-{{letterA}}></div> nor <div data-ng:model="foo-{{letterB}}"></div> are interpolated.
I'm looking for a way to dynamically load one of several inline templates.
Pardon me if this has already been asked before, but I searched and couldn't find it.
I believe Radim Köhler has the correct answer. Just before it was posted, I hacked together something to load directives from another directive like this:
angular.module('myApp', []).directive('loadTmpl', function($compile) {
return {
restrict: 'A',
replace: true,
link: function($scope, $element, $attr) {
$element.html("<div data-card-"+$attr.loadTmpl+"></div>");
$compile($element.contents())($scope);
}
};
});
And:
<div data-load-tmpl="{{directiveName}}"></div>
I think that's the minimalist approach, but there's probably something wrong with it, so just look at the answer below.
Let's adjust it this way (the udpated fiddle). The view:
<div my-selector name="letterA"></div>
<div my-selector name="letterB"></div>
the controller:
function myCtrl($scope) {
$scope.letterA = 'bar';
$scope.letterB = 'baz';
}
And here is new directive mySelector, containing the selector
.directive('mySelector',
[ '$templateCache','$compile',
function($templateCache , $compile) {
return {
scope: {
name: '='
},
replace: true,
template: '',
link: function (scope, elm, attrs) {
scope.buildView = function (name) {
var tmpl = $templateCache.get("dir-foo-" + name);
var view = $compile(tmpl)(scope);
elm.append(view);
}
},
controller: ['$scope', function (scope) {
scope.$watch('name', function (name) {
scope.buildView(name);
});
}],
};
}])
.run(['$templateCache', function ($templateCache) {
$templateCache.put("dir-foo-bar", '<div data-foo-bar></div>');
$templateCache.put("dir-foo-baz", '<div data-foo-baz></div>');
}])
In case you like it, all credits goes to Render a directive inside another directive (within repeater template) and AngularJS - Directive template dynamic, if you don't, blame me.

Angular and youtube iframe issue

I'm trying to add a youtube video to my app, but angular removes the iframe code and does not appear, I'm using this
<div class="content-read" ng-bind-html="data.content"> </ div>
try using ng-bind-html-unsafe, but I think this was removed from the current version of angularjs
I'm using angular 1.2.3
I have also this
app.config(['$sceDelegateProvider', function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'http://www.youtube.com/**',
]);
}]);
Any ideas?
thanks
the best solution I found, is to create a directive that meets the function of ng-bind-html-unsafe
app.directive('ngBindHtmlUnsafe', ['$sce', function($sce){
return {
scope: {
ngBindHtmlUnsafe: '=',
},
template: "<div ng-bind-html='trustedHtml'></div>",
link: function($scope, iElm, iAttrs, controller) {
$scope.updateView = function() {
$scope.trustedHtml = $sce.trustAsHtml($scope.ngBindHtmlUnsafe);
}
$scope.$watch('ngBindHtmlUnsafe', function(newVal, oldVal) {
$scope.updateView(newVal);
});
}
};
}]);

Categories