How do I insert a partial from a directive? - angularjs

I have a custom directive like below. In it I'd like to insert html from a partial:
.directive('myDirective', function($parse){
return {
restrict: 'A',
scope: { foo: '=' },
link: function(scope, element, attrs){
//add children to element[0] using html from partials/content.html
//...
}
});
Google/Stack doesn't reveal much, is there a way to do this or am I not meant to use directives in this way?

There are 3 possible things that you can do
You could either make $templateRequest to the html page, which internally make an ajax to fetch html & then put that html inside the $templateCache.
Code
$templateRequest('mypath.html').then(function(res){
//inside you could have html content in res.data;
var html = res.data;
})
You could put that html content inside $templateCache service inside run block & then use it whenever required using $templateCache.get('templateName')
Code
app.run(function($templateCache){
$templateCache.put('mytemplate.html', '<div>My HTML</div>')
})
//inside directive do below thing
var html = $templateCache.get('mytemplate.html');
Place the html content inside script block which will have type="text/ng-template" which will again force this template to put inside the $templateCache service. and this template will make you available instantly.
Markup
<script type="text/ng-template">
<div>My Content<div>
</script>
//inside directive you need to access it from $templateCache.
var html = $templateCache.get('mytemplate.html');

Related

Angular JS: Directive content is not available in Java script function

I have a div which has ng-click. When I click on that div, it calls a function which gets script content from a Directive and I append that to another div and access the content of the script. But when I retrieve the content of the directive I am getting directive name not the content. I want to get the content.
The function I call:
$scope.someFunction = function(){
var appendHtml = $compile("<my-custom-directive></my-custom-directive>")($scope);
$("#someId").append(appendHtml)
//But when i append I am seeing as <my-custom-directive></my-custom-directive> in html not the actual content
$(""#someId"").find('script')
}
Directive:
app.directive('myCustomDirective', function ($compile) {
return {
restrict: 'E',
templateUrl: '/somecontent.html',
replace: true,
link: function ($scope, elem, attr, ctrl) {}
};
});
Somecontent.html
<script type="text/template">
<div class="arrow" style="left: 50%;"></div>
some elements here
</div>
</script>
The HTML where I call from:
<div ng-click="someFunction()">
<div id="someId">
<my-custom-directive></my-custom-directive>
//But Here I am seeing this, when calling
$(appendHtml).find('script') in my javascript function, after Javasciprt function call is done, It works fine. But i want to see actual content here when calling $(""#someId"").find('script')
<div>
</div>
it is not a good practice.
you can use ng-if and binding instead , like the follwing:
HTML
<div ng-click="someFunction()">
<div id="someId">
<div ng-if="$scope.isVisible">
<my-custom-directive></my-custom-directive>
</div>
//But Here I am seeing this, when calling
$(appendHtml).find('script') in my javascript function, after Javasciprt function call is done, It works fine. But i want to see actual content here when calling $(""#someId"").find('script')
<div>
</div>
controller:
$scope.isVisible = false;
$scope.someFunction = function(){
$scope.isVisible = true;
}
you can also pass isolate scope param to your directive and check the param in the directive template
It's possible that you're just not using jQuery or jqLite to select elements correctly.
Your someFunction might need to look more like this:
vm.someFunction = function () {
var appendHtml = $compile('<my-custom-directive></my-custom-directive')($scope);
angular.element(document).find('some-id-element').append(appendHtml);
};
I put together this plunk that I think might achieve what you're trying to do.
Does this approximate your goal?

AngularJS custom directives not working when using ng-include "Object #<Scope> has no method"

So I decided after much debate, to split my webpage into two parts, one for ie7 and another for ie8+. I have many
<!-- if lte ie7--->
scattered around, and I just want to separate the html as much as possible. Sure it's heavier maintenance, but whatev.
So as I moved my html content from the main.html to submain.html, I noticed one of my custom directives wasn't working.
Note: All my javascript gets loaded AFTER I load the html content.
I have a directive called ng-map, where if this attribute appears on any div with an ID, it'd call mapquest to fill in the div with an interactive map. Currently this works.
However, if I move the directive:
<div ng-map id="map"></div>
out of main.html and place it into submain.html and add this in my main.html:
<div ng-include="'view/submain.html'">
it doesn't work, even though my submain.html loads properly.
It gives me the error: "Error: Object # has no method 'initMap'"
This is what my directive looks like:
mapapp.app.directive('ngMap', ['logger', '$http', function (logger, $http) {
var directiveDefinitionObject = {
restrict: 'A',
controller: function link($scope, $element) {
$scope.shouldMapLoadOnPageLoad = true;
$scope.loadCodeAndMap =
function () {
var key = {...};
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "http://www.mapquestapi.com/sdk/js/v7.0.s/mqa.toolkit.js?key=" + key;
document.body.appendChild(script);
};
$scope.loadCodeAndMap();
$scope.initMap = function () {
...
}
}
};
return (directiveDefinitionObject);
}]);
Any help in understanding what is happening here is appreciated.
Okay figured it out, but I don't have complete understanding.
When I load up my html content, controller, and directives, I was able to call the $scope.initMap function located in my directive from a $watch on my controller.
So this worked:
controller:
$scope.$watch('blahData', function(newVal, oldVal) {
$scope.initMap();
}
directive:
$scope.initMap = function() { .. }
however, when I change my html to load via ajax (which I assume that's what ng-include does to fetch the html from a location, you need to change the above logic.
So the previous html goes from this:
<html><head></head>
<body>
<!-- Stuff -->
<div>Hello!</div>
<!-- More Stuff -->
</body></html>
to
<html><head></head>
<body>
<!-- Stuff -->
<!-- Home.html has <div>Hello!</div> -->
<div ng-include="'Template/Home.html'" />
<!-- More Stuff -->
</body></html>
Then the controller becomes something like this:
$scope.initMap = false; //not a function anymore
$scope.$watch('blahData', function(newVal, oldVal){
$scope.initMap = !$scope.initMap;
}
and the directive becomes:
$scope.$watch('$scope.initMap', function() { ... }
So the directive now watches the data happening from the controller. Now, if your directive doesn't include scope: '=' for the directive options, then you have to access the controller scope as a parent:
$scope.$watch('$scope.$parent.initMap, function() { ... }
that's because scope: '=' binds the local $scope on the directive to the parent scope (the controller).

AngularJS - Add directive from within controller

I have defined the following directive:
app.directive('copyExpenditure', function(){
return {
restrict: 'A',
scope: true,
template: '<button ng-click="copyExpenditure()">click me</button>'
}
});
If I add this directive directly into the html it works as expected.
<div copy-expenditure></div>
Now I'm creating a grid from within a controller and want to dynamically add to each row the copyExpenditure directive. For this task I'm using Slickgrid and a custom Formatter.
var LinkFormatter = function (row, cell, value, columnDef, dataContext) {
var tag = '<div copy-expenditure></div>';
return tag;
}
But it seems as this custom formatter is not rendered as a directive, but only as HTMl. Any idea what to do? My goal is only to call a scope function using ng-click and a tag rendered by the LinkFormatter.
You should do:
$compile(angular.element('<div copy-expenditure></div>'))($scope);
and if you have some values passed into it from scope, you do this after compile:
$scope.$digest();

Replace the html of an element with the content of an external template in a directive?

I'm trying to create a directive which is a sidebar in my shell page that will change accordingly whenever a new route is hit, and will populate itself with the sub menu items relevant to that parent route. I have 4 different menus which are external templates and i want the contents of those html files to replace the menu, the link function of my directive looks like this so far:
link: function(scope, element, attrs, ngModel) {
scope.$on("$routeChangeSuccess", function (event, current, previous) {
element.html('<div ng-include=\'enterprisesMenu.html\'></div>');
});
};
But the element is not updating, however when i use inline templates the elements updates according, but because each template is complex i prefer not to have that html inside my directive, I've also tried element.html('<div ng-include src=\'enterprisesMenu.html\'></div>');
Any ideas?
Try $compile:
element.html($compile('<div ng-include=\'enterprisesMenu.html\'></div>')
(scope));
You could achieve this result by dynamically ng-including the desired template. For instance:
HTML:
<div class="your-sidebar" ng-controller="SidebarCtrl">
<div ng-include="sidebar.url" ></div>
</div>
Controller:
app.controller("SidebarCtrl", function($scope) {
$scope.sidebar = {
url: "initial-url"
};
$scope.$on("$routeChangeSuccess", function(event, current, previous) {
// decide potentially new value for $scope.sidebar.url
$scope.sidebar.url = newValueCalculatedAbove;
});
});
This solution does not require a directive, only an extra controller. It can be done with directive too, the HTML above is the template of the directive and the JS code the controller (no link function required).

Angular binding inside an inline ckeditor

I'm using inline editing with CKEditor, and I'd like to bind an element to an angular scope value.
<div contentEditable="true">
<p>Here is the value: {{testval}}</p>
</div>
testval should update in the same manner as it would outside the editor.
To protect this text in the editor, I'd like to do something similar to the placeholder plugin. In other words I plan to have a placeholder, dynamically displaying the final text rather than just the placeholder.
I've seen several examples of how to bind the entire contents with angular, but not individual elements. I'm still fairly new to both angular and ckeditor, so any help or pointers would be much appreciated.
It sounds to me like you will need to use a directive for what you want. I might be soewhat off because I'm not completely familiar, but goig by what you've provided, let's assume this example.
html
<body ng-app="myApp">
<div content-editable content="content"></div>
</body>
javascript
angular.module('myApp', [])
.directive('contentEditable', function() {
restrict: 'A',
replace: true,
scope: {
// Assume this will be html content being bound by the controller
// In the controller you would have:
// $scope.content = '<div>Hello World</div>'
content: "="
},
template: '<div contentEditable="true"><p>Here is the value {{ content }}</p></div>'
});
Still not sure if I completely comprehend, but let me know if I'm getting closer.
I assume that you want to bind the HTML text in model to the element. I used ng-bind-html to render what is in the model and I created the directive ck-inline to add the inline feature and bind the model to the changes that happen in the inline editor. This directive requires a ng-bind-html to work and you also need to have ngSanitize added to your module. Add directive ck-inline to your element and
I also use $timeout because I noticed that if I don't the text is rendered and then ckeditor somehow deletes all the values which messes up the model (this does not happen with the non-inline option). Here is the code.
yourModule.directive('ckInline', ['$sce', '$timeout', function($sce, $timeout){
return{
require : '?ngBindHtml',
scope:{value:"=ngBindHtml"},
link : function(scope, elm, attr, ngBindHtml)
{
$timeout(function()
{
var ck_inline;
elm.attr("contenteditable", "true");
CKEDITOR.disableAutoInline = true;
ck_inline = CKEDITOR.inline(elm[0]);
if (!attr.ngBindHtml)
return;
ck_inline.on('instanceReady', function()
{
ck_inline.setData(elm.html());
});
function updateHtml()
{
scope.$apply(function()
{
scope.value = $sce.trustAsHtml(ck_inline.getData());
});
}
ck_inline.on('blur', updateHtml);
ck_inline.on('dataReady', updateHtml);
});
}
};
}]);

Resources