Issue with Multi Transclude in Angular - javascript

I am using multitranscldue in angular js.I am having a directive like below.
(function(){
angular.module("MyDirective",['multi-transclude'])
.directive("myDirective",function(){
var MyLink = function(scope,element,attr){
scope.title = attr.title;
}
return{
restrict : 'EA',
scope: {title:"="},
transclude:true,
templateUrl:"directive.html",
link: MyLink
}
});
}())
The html for directive is like
<div >
<div>
<span data-ng-bind="title"></span>
<div ng-multi-transclude="card-body"></div>
</div>
</div>
In my main html class, I am using the directive like below.
<my-directive title="asdasdas">
<div name="card-body">
{{title}}
</div>
</my-directive>
I am getting an error like
Error: Illegal use of ngMultiTransclude. No wrapping controller.
Please help me with this.
The link to plunker is here

you have to add ng-multi-transclude-controller to your directive's HTML template, as follows:
<div ng-multi-transclude-controller>
<div>
<span data-ng-bind="title"></span>
<div ng-multi-transclude="card-body"></div>
</div>
</div>

Related

AngularJS ng-repeat doesn't work in a directive that rewrites HTML [duplicate]

This question already has answers here:
Angular directives - when and how to use compile, controller, pre-link and post-link [closed]
(8 answers)
Closed 5 years ago.
I have a directive that needs to do some HTML rewriting on its contents before it gets compiled. I've found a way to do that but it doesn't seem to work for ng-repeat.
HTML
<body ng-controller="MainCtrl">
<div ng-repeat="source in sources">
<p>
{{ source.name }}
</p>
</div>
<div my-template>
{{ sources }}
<div ng-repeat="source in sources">
<p>
{{ source.name }}
</p>
</div>
</div>
</body>
JS
var app = angular.module('plunker', []);
app.directive("myTemplate", ['$compile', function ($compile) {
return {
restrict: 'A',
link: function ($scope, $element, $attributes) {
var html = $element.html();
console.log(html); // problem?
$element.html(html);
$compile($element.contents())($scope);
}
}
}])
app.controller('MainCtrl', function($scope) {
$scope.sources = [{ name: "source1"}, { name: "source2"}];
});
The output is:
source1
source2
[{"name":"source1"},{"name":"source2"}]
So the sources variable is visible in the directive's scope but ng-repeat fails anyway. console.log(html) shows this in a console:
{{ sources }}
<!-- ngRepeat: source in sources -->
Which hints at ng-repeat being evaluated/compiled before my directive but I don't know where to go further from this.
Plunker: http://plnkr.co/edit/1NJngUK27IRAp0ELVHFc?p=preview
As georgeawg noticed, changing from "link" to "compile" phase helps in this case.
You need to use transclude option in directive, see the example. Important you reference a old version of AngularJS (1.0.8), I use in the example 1.4.1.
https://docs.angularjs.org/api/ng/directive/ngTransclude
angular.module('transcludeExample', [])
.directive('myTemplate', function(){
return {
restrict: 'A',
transclude: true,
template: '<ng-transclude></ng-transclude>'
};
})
.controller('ExampleController', ['$scope', function($scope) {
$scope.sources = [{ name: "source1"}, { name: "source2"}];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>
<div ng-app="transcludeExample">
<div ng-controller="ExampleController">
<div my-template>
{{ sources }}
<div ng-repeat="source in sources">
<p>
{{ source.name }}
</p>
</div>
</div>
</div>
</div>

Illegal use of ng-Transclude directive in the template

When I use ngTransclude, the page seems good,but got console error:
Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element: {0}
I found the root cause: in index.js I used $compile to compile the modal directive.It seems $compile can't work with ng-transclude. Do you have some suggestion to fix this issue?
Here is the code
directive.js:
myApp.directive('modal', function () {
return {
restrict: 'E',
templateUrl: 'modal/modal.html',
replace: true,
transclude: true,
scope: {},
link: function(scope, element, attrs){
},
controller: ['$scope', function transcludeController($scope) {
}]
}
});
template.html:
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"> ... </div>
<div class="modal-body">
<ng-transclude></ng-transclude>
</div>
<div class="modal-footer"> ... </div>
</div>
</div>
</div>
index.html:
<modal>
<input type="text" id="test"/>
</modal>
index.js:
$scope.test = 'test';
$("#test").attr("ng-model", "test");
$compile(modal)($scope);
Please check the Plunker link. Its working there. if you can update the link with your code perhaps we can help you.
Link: https://plnkr.co/edit/ey1fXDwEOVtA64R6Io3q?p=preview

AngularJS directive is not getting data passed in scope

Here is my html snippet :
<div ng-controller="ctrl">
<custom-tag
title = "name"
body = "content">
</custom-tag>
</div>
Here is controller and directive written:
var mod = angular.module("main_module",[]);
//Controller
mod.controller("ctrl",function($scope) {
$scope.name="Page Title";
$scope.content="sample_template.html";
});
//Directive
mod.directive("customTag", function() {
return {
'restrict' : 'E',
'scope' : {
'title' : '=',
'body : '='
},
'templateUrl' : 'directive_template.html'
};
});
<!-- directive_template.html -->
<div>
<div>{{title}}</div>
<div ng-include="'{{body}}'"></div>
</div>
The actual html rendered by directive is this :
<div>
<div ng-binding></div>
<!-- ngInclude: '{{body}}' -->
</div>
Clearly it is not getting the directive scope variables from attributes in <custom_tag>
Please tell me why it is happening and how I resolve this issue.
Thanks
Check the console for errors extra quotes and {{}} braces were breaking things.
<div>
<div>{{title}}</div>
<div ng-include="body"></div>
</div>
http://plnkr.co/edit/G9JfIJGhSghUbgkKLXnV?p=preview

accessing other scope variables inside custom template

I'm trying to display files inside each folder/directory.
I'm using custom directive to disply each of the directories as follows (this part works).
But it fails to resolve the {{file}} variable inside custom template folderListing.html. Can somebody please correct me where I'm going wrong ?
folderListing.js
app.directive('folderListing', function(){
return {
restrict: 'E',
scope: {
listing:'='
},
templateUrl: 'js/directives/folderListing.html'
};
});
RdaController.js
app.controller('RdaController', ['$scope','RdaService', function($scope,RdaService) {
$scope.folders = ['RDA Server Folder','CTP Outbox', 'CTP Inbox', 'CTP Jobs'];
$scope.sendToCTP = function(file){
return RdaService.SendFileToCTP(file);
};
$scope.listOfFiles = ['learn_javascript.pdf', 'HTML Made Easy.pdf', 'AngularJS for everybody.pdf'];
}]);
index.html
<folder-listing listing="folder" ng-repeat="folder in folders"></folder-listing>
folderListing.html
<div class="row">
<div class="col-md-3" id="{{listing}}">
<table class="table table-striped">
<h3> {{ listing }} </h3>
<div class="row">
<div class="col-md-3" ng-repeat="file in listOfFiles">
{{file}}
</div>
</div>
<td><span class="btn-group" role="group"><button type="button" class="btn btn-default" ng-click="sendToCTP(file)">Execute</button></span></td>
</table>
</div>
</div>
With this:
scope: {
listing:'='
},
You have created an isolate scope passing only listing to the directive. You need to change this to:
scope: {
listing: '=',
listOfFiles: '=',
sendToCTP: '&sendToCtp'
},
To pass the function you'll have to add a send-to-ctp="sendToCTP(file)" attribute on your directive. However, in your template your button with ng-click="sendToCTP(file)" is outside your ng-repeat so file will always be undefined.

Ng-repeat in custom directive does not repeat

I'm trying really hard, but I can't find where is my problem.
I created a custom directive and it should iterate some HTML to draw the right content on the screen.
The problem is that my ng-repeat does not iterate my array. I search on stackoverflow but what I found didn't help me.
Here is my directive (it's in an external file):
app.directive('logtab', function(){
return {
restrict: 'E',
templateUrl: 'view/templates/log-tab.html',
replace: true,
controller: ['$scope', 'api', function($scope, api) {
$scope.logState = false;
$scope.logData = [1,2,3,4];
$scope.loadLog = function() {
api.doRequest({
path : $scope.path,
method : "GET",
broadcast : BK_LOG
});
};
var bk = $scope.$on(BK_LOG, function(key, value){
$scope.logState = true;
console.log($scope.logData);
bk();
});
}]
};
});
And here is the directive HTML that will be rendered:
<md-tab ng-click="loadLog()" label="{{i18n['REVISIONS']}}">
<div layout="row" layout-align="center" layout-padding ng-show="!logState">
<div layout="column">
<div>
<md-progress-circular md-mode="indeterminate" md-diameter="130"></md-progress-circular>
</div>
<div>
{{i18n['LOG_LOAD']}}
</div>
</div>
</div>
<div layout="row" ng-show="logState" layout-padding>
<div layout="column">
<div ng-repeat="xyz in logData">
{{xyz}}
SOME CONTENT HERE
</div>
</div>
</div>
</md-tab>
Thanks in advance!
I removed other components from your directive code and kept it at bare minimum. The code is working fine as expected. Please see below.
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body ng-app="myApp" >
<logtab></logtab>
<script src="angular.js" type="text/javascript "></script>
<script src="app.js" type="text/javascript "></script>
</body>
</html>
app.js
var myApp = angular.module('myApp', []);
myApp.directive('logtab', function(){
return {
restrict: 'E',
templateUrl: 'log-tab.html',
replace: true,
controller: ['$scope', function($scope) {
$scope.logState = false;
$scope.logData = [1,2,3,4];
console.log('hi');
}]
};
});
log-tab.html
<div>
{{logData}}
<div layout="row">
<div layout="column">
<div ng-repeat="xyz in logData">
{{xyz}}
</div>
</div>
</div>
</div>
Please use a couple of console.log's to identify the exact location. I suspect that there must be some thing wrong with the other parts of the directive or may be logState is set to false??
You can always separate the controller from the directive:
app.directive('logtab', function(){
return {
restrict: 'E',
templateUrl: 'view/templates/log-tab.html',
replace: true,
scope: {
log: '='
}
};
});
Then in your controller
app.controller('MyController', ['$scope', 'api', function($scope, api) {
$scope.logTab = {
state: false,
data: [1, 2, 3, 4],
loadLog: function() {
api.doRequest({
path : $scope.path,
method : "GET",
broadcast : BK_LOG
});
}
};
var bk = $scope.$on(BK_LOG, function(key, value){
$scope.logTab.state = true;
console.log($scope.logTab.data);
bk();
});
}]);
Then change your HTML to:
<md-tab ng-click="log.loadLog()" label="{{i18n['REVISIONS']}}">
<div layout="row" layout-align="center" layout-padding ng-show="!log.state">
<div layout="column">
<div>
<md-progress-circular md-mode="indeterminate" md-diameter="130"></md-progress-circular>
</div>
<div>
{{i18n['LOG_LOAD']}}
</div>
</div>
</div>
<div layout="row" ng-show="log.state" layout-padding>
<div layout="column">
<div ng-repeat="xyz in log.data">
{{xyz}}
SOME CONTENT HERE
</div>
</div>
</div>
</md-tab>
And call it with
<logtab log="logTab"></logtab>
Updated my answer based on OP's explanation.
Created a fiddle here: https://jsfiddle.net/frishi/bzbbo5da/14/
I simplified the directive definition a little, removed the api part of it.
I also changed the directive's template to include the ng-repeat part of it.
//....
restrict: 'E',
template: `<p><div ng-repeat="xyz in logData">
{{xyz}}
SOME CONTENT HERE
</div></p>`,
replace: false,
scope: true, // <- needs to be set
//....
You are missing the scope parameter in the directive definition object. You have to set it to scope: true for your directive's template to be able to access a variable defined on the directive controller's scope.

Categories

Resources