Angular directive controller scope inheritance - javascript

Lets start with some code
Html:
<rd-search-set type="'ActiveProfileContact'">
<form class="navbar-form navbar-static-top" role="search">
<rds-input />
</form>
</rd-search-set>
rds-input template:
<div class="input-group rd-search-wrap">
<div class="input-group-addon">
<i class="fa fa-search"></i>
</div>
<input type="text" value="" class="form-control" placeholder="{{'FIND_CONTACT' | translate | capitalize}}..." ng-modal="src.value" />
<div class="rd-search-state">
<i class="fa spin2D fa-spinner" ng-if="src.isBusy"></i>
<span class="text-muted rd-search-result" ng-if="!src.isBusy">{{src.amountString}}</span>
</div>
Javascript / AngularJs:
angular
.module("App")
.directive("rdSearchSet", rdSearchSet)
.directive("rdsInput", rdsInput);
function rdSearchSet() {
var directive = {
restrict: 'E',
scope: {
onSearch: "=onSearch",
searchForType: "=type",
relatedGuids: "=rdSearchRelatedGuids",
searchEventType: "=rdSearchEventType",
},
controller: "SearchController",
controllerAs: "src",
bindToController: true,
replace: false,
};
return directive;
}
rdsInput.$inject = ["rdBaseUrl"];
function rdsInput(rdBaseUrl) {
var directive = {
restrict: 'E',
replace: true,
templateUrl: rdBaseUrl + "Partials/Directives/Search/rdsInput.html",
require: "^rdSearchSet",
transclude: true,
scope: false,
};
return directive;
}
The problem
I'm having alot of trouble getting / setting data on the controller of the rdSearchSet directive. Last thing I tried is setting the rdsInput directive scope property to false, hoping that I can access the parent scope values using the controllerAs: "src" property of rdSearchSet.
My question in short: What is the best way to access the parent directive's controller(as) scope as transparent as possible? Like, use a Directive to load html and bind to parent directive scope properties, both ways.
EDIT:
I have moved the rdSearchSet directive html to a template that looks like this:
<form class="navbar-form navbar-static-top navbar-royal" role="search">
<rds-input />
</form>
<rds-list />
rdSearchSet.$inject = ["rdBaseUrl"];
function rdSearchSet(rdBaseUrl) {
var directive = {
restrict: 'E',
scope: {
onSearch: "=onSearch",
searchForType: "=type",
relatedGuids: "=rdSearchRelatedGuids",
searchEventType: "=rdSearchEventType",
},
templateUrl: rdBaseUrl + "Partials/Directives/Search/rdsSearchSet.html",
controller: "SearchController",
controllerAs: "src",
bindToController: true,
replace: false,
};
return directive;
}
The problem that still exists is that I am not able to use the ControllerAs prefix. The
text input field in rdsInput uses a ng-model="src.value" but the
value is not set in the rdSearchSet's Controller.

Two problems ... one is a simple typo for ng-model where you have ng-modal.
The other is isolated scope only works when you use a template, it doesn't work for existing html within the element.
If you move the <form> to a template your code will work
<rd-search-set></rd-search-set>
JS
function rdSearchSet() {
var directive = {
restrict: 'E',
templateUrl:'search.html',
scope: {
.....,
},
controller: "SearchController",
controllerAs: "src"
};
return directive;
}
DEMO

Related

Multiple instance of angular directive will return different value. Then how to get all the value in single event

I have the problem where i created a custom directive in which i created a text box. And i am using this multiple time on a template. The problem is that as i change on one text box i want to get the value of all field (or directives)
<mydirective type="text" name="x" />
<mydirective type="text" name="y" />
Here is the directive view template
<div><input type="text" name="sender" ng-model="cstmfld" value="" ng-change="sendResponse()" /></div>
<script>
angular.module('myApp').directive('mydirective', function(){
return {
restrict: 'EA',
replace: true,
transclude: true,
scope: {
label: '#',
input: '=',
currencyList: '=',
fieldModel:'='
},
templateUrl: 'views/field.html',
controller: function($scope, $element, $attrs, $http){
$scope.sendResponse = function(){
//do something so i get both filed value
}
}
}
});
</script>
Do i making any mistake or is it possible

Angular transclude directive inside another transclude directive

I have an angular directive inside of another directive. Both use transclude: true.
I would expect if I had the following code (taken from the plunker) that I would see the same thing 3 times.
https://plnkr.co/edit/iIyU65WdMr4jDQyKZpt1?p=preview
JS:
angular.module('app', [])
.directive('myButton', myButton)
.directive('directiveWithDirective', directiveWithDirective)
.directive('directiveWithDiv', directiveWithDiv);
function myButton(){
return {
restrict: 'E',
transclude: true,
template: '<button ng-transclude> </button>'
};
}
function directiveWithDirective(){
return {
restrict: 'E',
transclude: true,
template: '<my-button ng-transclude> </my-button>'
};
}
function directiveWithDiv(){
return {
restrict: 'E',
transclude: true,
template: '<div ng-transclude> </div>'
};
}
HTML:
<div ng-app="app">
<my-button>
A Button
</my-button>
<br>
<directive-with-directive>
A Button
</directive-with-directive>
<br>
<directive-with-div>
<div>
<my-button>
A Button
</my-button>
</div>
</directive-with->
</div>
my-button and directive-with-div behave as I would expect. They include their content in the template.
However, directive-with-directive does not. I would expect the text "a button" to be included inside of my-button then, my-button be expanded into a button. Instead I see a blank directive:
<my-button ng-transclude=""> </my-button>.
I expect
<my-button ng-transclude=""><button>A Button</button> </my-button>
My questions are:
What am I misunderstanding about this? Is it related to the order in which directives are expanded by angular? Can I change this?
How can I achieve having a directive with transclusion within another transcluded directive.
I think you can solve your problem with this :
function directiveWithDirective(){
return {
restrict: 'E',
transclude: true,
template: '<my-button><ng-transclude /> </my-button>'
};
}

Using ui-tinymce Directive in Another Directive

I'm trying to use the ui-tinymce directive inside of another directive:
angular.module("risevision.widget.common.font-setting", ["ui.tinymce"])
.directive("fontSetting", ["$templateCache", function ($templateCache) {
return {
restrict: "AE",
template: $templateCache.get("_angular/font-setting/font-setting.html"),
transclude: false,
link: function ($scope, element, attrs) {
$scope.tinymceOptions = {
menubar: false,
statusbar: false
};
}
};
}]);
And _angular/font-setting/font-setting.html:
<div class="row">
<div class="col-md-12">
<textarea ui-tinymce="tinymceOptions" ng-model="tinymceModel"></textarea>
</div>
</div>
The TinyMCE editor shows up, but it's ignoring the configuration options I've set in $scope.tinymceOptions. That is, the menu bar and status bar still show.
Any thoughts as to why it's not working?
Thx.
I know I'm late to the party but I'm going to answer you in case someone has the same issue and can't find the answer.
TinyMce needs to be loaded only when the tinymceOptions variable has data so you need to wrap it in an ng-if:
<div class="row">
<div class="col-md-12" ng-if="tinymceOptions">
<textarea ui-tinymce="$parent.tinymceOptions" ng-model="$parent.tinymceModel"></textarea>
</div>
</div>
You can avoid using $parent (elements inside ng-if have their own scope) using controller as inside the directive if you are using Angular >1.4:
app.directive('someDirective', function () {
return {
scope: {},
bindToController: {
someObject: '=',
...
},
controllerAs: 'ctrl',
controller: function () {
var ctrl = this;
ctrl.message = 'Object loaded.';
},
template: '<div ng-if="ctrl.someObject">{{ctrl.message}}</div>'
};
});

Using ng-change and ng-model when wrapping directives

Using angular-strap I can use the select directive like this:
<div class="btn-group">
<span class="btn btn-default" disabled>Type:</span>
<button type="button"
class="btn btn-default"
ng-model="vm.options.type"
ng-change="vm.doSomething(vm.options)"
bs-options="o.key as o.label for o in vm.types"
data-multiple="1"
bs-select>
</button>
</div>
But I want to wrap this markup in another directive, my-select, so I could use it like this:
<my-select label="Type"
ng-model="vm.options.type"
ng-change="vm.doSomething(vm.options)"
bs-options="o.key as o.label for o in vm.types">
</my-select>
I was able to pass bs-options by simply adding element attribute during compile phase of directive, but I can't get ng-model and ng-change to work the same way it would work without wrapping bs-select directive.
I've read how to use ng-model in conjunction with ng-change by using ngModelController, but I would simply like to pass it down to to the wrapped bs-select directive.
EDIT: Adding directive code
NOTE: Code contains different prefix for my directive, I'm aware of that.
angular
.module('ticketApp.ui')
.directive('ttSelect', ttSelect);
function ttSelect() {
return {
restrict: 'E',
replace: true,
require: 'ngModel',
bindToController: {
label: '#ttLabel',
ngModel: '='
},
templateUrl: 'ui/tt-select/tt-select.html',
controller: ttSelectController,
controllerAs: 'vm',
link: link,
compile: compile
};
function link(scope, element, attrs, ngModel) {
ngModel.$viewChangeListeners.push(function () {
console.log('changed');
});
}
function compile(element, attrs) {
var bsOptions = document.createAttribute('bs-options');
var bsSelect = element.children()[1];
bsOptions.nodeValue = attrs.ttOptions;
bsSelect.attributes.setNamedItem(bsOptions);
}
}
function ttSelectController() {
this.label = 'Label';
}

How to pass evaluated values to a custom element directive?

I have a custom element directive with the following template:
<div>
<input value="{{dataFromRootScope}}" />
</div>
And definition:
dirModule.directive('myDirective', function() {
return {
restrict: 'E',
templateUrl: '/Scripts/app/directives/myDirective.html'
};
}
);
I would like to use the directive as shown below:
<my-directive my-value="{{dataFromScope}}"></my-directive>
i.e. I want to use the evaluated dataFromScope value inside my custom directive as dataFromRootScope. How can I reach this?
You can use isolated scope two-way binding:
dirModule.directive('myDirective', function() {
return {
scope: {
model: '=myValue'
},
restrict: 'E',
templateUrl: '/Scripts/app/directives/myDirective.html'
};
});
Where directive template is
<div>
<input ng-model="model" />
</div>
and usage is
<my-directive my-value="dataFromScope"></my-directive>
Demo: http://plnkr.co/edit/Npiq2hCO4tQHmakG4IAe?p=preview
I want to use the evaluated dataFromScope value inside my custom
directive as dataFromRootScope. How can I reach this?
Well you have two options to achieve this.
Option-1: Create an isolated scope for your directive
This way, you would need to assign value of dataFromRootScope from myValue. The = operator ensures two-way binding.
app.directive('myDirective', function() {
return {
restrict: 'E',
scope:{
dataFromRootScope: '=myValue'
},
templateUrl: 'myDirective.html'
};
}
);
'dataFromScope' will not be available in myDirective because it has isolated scope. You can access it via dataFromRootScope(see how its getting its value from myValue)
<div>
<input value="{{dataFromRootScope}}" />
</div>
Demo-1
Option-2: Enjoy shared scope.
In this case, you dont need to create an isolated scope. You can simply use dataFromScope in your directive template OR, if you really want to access it as dataFromRootScope in your template, simply assign it in your link function.
app.directive('myDirective', function() {
return {
restrict: 'E',
templateUrl: 'myDirective.html',
link:function(scope,ele,attr){
scope.dataFromRootScope = scope.dataFromScope
}
};
}
);
<div>
<input value="{{dataFromRootScope}}" />
</div>
Demo-2
You can use the '#' sign :
dirModule.directive('myDirective', function() {
return {
scope: { myValue: '#' },
restrict: 'E',
templateUrl: '/Scripts/app/directives/myDirective.html'
};
});
The '#' sign binds the evaluated value of the DOM attribute to the directive.
You can then use the directive as you asked :
<my-directive my-value="{{dataFromScope}}"></my-directive>

Categories

Resources