Directive with transclude, data binding not working in templateUrl - angularjs

I have a directive with transclude:true. However, the data binding works when i use a template:"" but not when i use templateUrl:""
Below you can find my directive. The rsCarousel.html template contains the same code as the template"" property.
When using the template property i get the vm.carouselId on screen but not when using the templateUrl property.
Why is this?
Thx,
(function () {
'use strict';
angular.module('skynetDashboard').directive('rsCarouseli', carouseli);
function carouseli(){
var directive = {
restrict:"EA",
scope:{
carouselData:"=",
carouselId:"#",
carouselOptions:"#"
},
transclude:true,
templateUrl:"js/directive/rsCarousel.html",
//template:"<strong>ID: {{vm.carouselId}}</strong><ul ng-transclude></ul>",
bindToController:true,
controllerAs:"vm",
link:link,
controller:controller
}
return directive
function link(scope){
console.log(scope.vm)
}
controller.$inject = [""]
function controller(){
}
}
})();

That is strange, scope binding should work in both cases.
Be sure that your template file is not cached by the browser (and using an old version of it).

Related

Is there a way to list a directive as a requirement for another directive?

I have a directive that I use for date-time input and I'd like to use it in the template for another directive.
The problem is that if I use the parent directive anywhere and I forget to include the child directive in the page, it fails silently.
Is there a way to make a directive require another directive?
I tried listing it in the require attribute, but then it fails even when DateTimeInput is included.
angular
.module('main')
.directive("newTransferPane", ["TransferService", function(TransferService){
'use strict';
return {
restrict: "A",
templateUrl: "Templates/NewTransferPane.html",
scope: true,
require: "DateTimeInput",
link: function ($scope){
$scope.secondTransfer = false;
$scope.transfer_date = new Date();
$scope.$watch("secondTransfer", function(){
TransferService.secondTransfer = $scope.secondTransfer;
});
}
};
}]);

Understand Bindings in Components

I don't get the binding in angular components. I have reworked this material FAB demo to a component. So there is no ng-controller directive anymore. However I cannot make the bindings of bindings: {isOpen: '='} to work. I get the following error:
Expression 'undefined' in attribute 'isOpen' used with directive 'tsButton' is non-assignable!
The code looks like this:
<div ng-cloak>
<md-fab-speed-dial
md-open="$ctrl.isOpen"
ng-mouseenter="$ctrl.isOpen=true"
ng-mouseleave="$ctrl.isOpen=false">
<!-- buttons and trigger -->
</md-fab-speed-dial>
(function () {
'use strict';
angular
.module('trip')
.component('tsButton', {
templateUrl: "app/component/button.component.html",
controller: ButtonController,
});
function ButtonController() {
var vm = this;
vm.isOpen = false;
};
}
})();
If I omit the bindings: {isOpen: '='} then md-open="$ctrl.isOpen" is not propagated.
A workaround is to define methods for ng-mouseenter="$ctrl.open()" and ng-mouseleave="$ctrl.close()" that in controller assign the correct boolean to vm.isOpen. But as I say it is just a workaround that makes the code longer, among other things.
isOpen: '=' was not working because I was giving it a primitive value. For this to work it had to be a reference of course.

What is the correct way to access controller that was required inside directive controller?

I have a directive with require property:
require: '^testBox'
now I want to get testBox controller inside controller of my directive. How should I do it?
I was trying to do so:
controller: function(){
this.testBox.user
}
but looks like it does not work.
It's clear for me how to get required controller inside link function. But is there a way to get it inside controller without using link?
Code on plunker.
This is still an open issue. So at the moment you can not just inject the required controller into your directive controller. I have updated your Plunker. It's definitely a bit hacky but the problem is; You cannot expose the TextBoxCtrl to the UserCtrl in either the pre or post link function because the controller gets executed first. So my idea is to use a watcher to observe a scope varibale called textBox. Once the value is defined I declare a variable on the UserCtrl and remove the watcher. Now you can simply use it in your template like so:
{{ user.textBox.name }}
Here is the code for the link function and the controller of the user directive:
link: function($scope, $element, $attrs, ctrl) {
$scope.textBox = ctrl
},
controller: function($scope) {
var vm = this;
var watcher = $scope.$watch('textBox', function(newVal) {
if(newVal) {
vm.textBox = newVal;
watcher();
}
});
}
However, you can also go with a link function instead. The required controller will be injected as the fourth parameter.
When you use controllerAs it's just added as a property of the underlying scope object (using the name you've defined). Knowing this, you can attach the parent controller instance as a property of your child controller instance as follows:
function exampleDirective() {
return {
require: '^testBox',
link: function (scope, element, attrs, testBox) {
scope.example.testBox = testBox;
},
controllerAs: 'example',
controller: function() {
// silly example, but you get the idea!
this.user = this.testBox.user;
}
}
};

Accessing ng-repeat scope on a custom directive

I'm having a go at a directive which will dynamically load a template based on a scope value passed into it.
I am using ng-repeat on my directive, and am using the iterated item as an attribute property:
<my-form-field ng-repeat="field in customFields" field="field">
In my directive I have the following code to set the template being used.
(function() {
'use strict';
angular
.module('app')
.directive('myFormField', myFormField);
function myFormField() {
var directive = {
restrict: 'E',
scope: {
field: '='
},
link: function(scope){
scope.getContentUrl = function() {
return 'app/modules/form_components/form_field/' + scope.field.type + '-template.html';
}
},
template: '<div ng-include="getContentUrl()"></div>'
};
return directive;
}
})();
Whilst the above works (which I found from other posts), I wonder if there is a better way.
For example I have seen examples of calling a function on the templateUrl config option instead, and then in that function access the scope attributes being passed in. When I tried this way, my field attribute was a literal 'field' string value (they are objects in my customFields array), so I think at that point the scope variables had not yet been evaluated.
With this current solution I am using, all of my templates get wrapped in an extra div since I am using ng-include, so I am just trying to make the rendered markup more succinct.
Any suggestions\advice is appreciated.
Thanks

angular.js controller as syntax template binding using $template cache service

i have already used angular js before but now i am using controller as syntax in angular js and i am not able to bind template.
My controller code:
(function () {
angular.module("vkApp")
.controller("Feeds", Feeds);
function Feeds(FeedSetting, FeedLoader, $templateCache, $compile) {
var vm = this;
FeedSetting.initializeSetting(vm);
//functions declaration
vm.addFeed = addFeed;
// function implementations
function addFeed(text) {
return FeedLoader.loadFeed("http://rss.cnn.com/rss/edition_world.rss")
.then(function (feedData) {
console.log(feedData.data.responseData.feed);
vm.feedList = feedData.data.responseData.feed;
var feedTemplate = $templateCache.get("feedTemplate");
feedTemplate.then(function (markup) {
$compile(markup.data)(vm).appendTo(angular.element("#FeedArea"));
});
return vm.feedList;
});
}
};
})();
My template is:
<h7>{{feed.feedList.title}}</h7>
feed.html page:
<div id="rightSide" ng-controller="Feeds as feed">
<div class="news-feed-wrapper" id="FeedArea">
</div>
</div>
when the binding is performed it gives me error in console
You need to make couple of changes
1)Replace this line
$compile(markup.data)(vm).appendTo(angular.element("#FeedArea"));
with
$compile(markup.data)($scope).appendTo(angular.element("#FeedArea"));
because behind the scene your custom variable vm bind with Angular $scope. So $compile would work the same like it was using classic controller with $scope syntax
2) And in your binding replace
<h7>{{feed.feedList.title}}</h7>
with
<h7>{{vm.feedList.title}}</h7>
3) And inside Feed.html
ng-controller="Feeds as feed"
should be
ng-controller="Feeds as vm"
After the above changes it should work.

Resources