Using ng-change and ng-model when wrapping directives - javascript

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';
}

Related

AngularJS dynamically ng-model name from parameter

Edit
How to set for this <input ng-model="this['newPlayer']['personal_info']['first_name']">
the ['newPlayer']['personal_info']['first_name'] dynamically from variable?
Something like this: <input ng-model="this[variable]">
You don't have to get it from the attributes just add this to your directive require: 'ngModel'
like this
app.directive("textInput", () => {
return {
templateUrl: "/text-input.html",
require: 'ngModel'
scope: true,
link: function($scope, $element, $attrs, ngModel) {
angular.element($element).append($scope[$attrs.myModel]);
}
}
});
and you have your different ngModel for each textInput instance in link function

angular directive in directive parent click

I'm creating a directive to show differences in text. For this directive, I need a couple of buttons which I've split up in directives. A simpliefied example would be:
.directive('differenceViewer', function($templateCache, $compile) {
return {
restrict: 'E',
scope: {
oldtext: '#',
newtext: '#',
template: '#',
heading: '#',
options: '=',
itemdata: '&',
method: '&'
},
replace: false,
link: (scope, element, attr) => {
element.append(angular.element($compile($templateCache.get(scope.template))(scope)));
}
};
}).directive('diffbutton', function() {
return {
restrict: 'E',
scope: {
method: '&'
},
template: '<button class="btn btn-sm btn-success" ng-click="method()">Rollback</button>',
replace: true,
terminal: true,
link: (scope, element, attr) => {
scope.directiveClick = function(){
console.log("directive method"); // is never called
}
}
}
})
I compile the html via a template script:
<script type="text/ng-template" id="differenceViewer.html">
<div class="ibox-footer">
<div class="row">
<div class="col-md-12">
<diffbutton method="clickedBtn()">Foo</diffbutton>
</div>
</div>
</div>
</script>
Where the diffbutton is created inside the html compiled by differenceViewer.
I need to call a method in the controller that is responsible for creating all the difference-views.
app.controller('MainCtrl', function($scope) {
$scope.clickedBtn = function() {
console.log('foo'); // is never called
}
})
Here's a plunker demonstrating the issue.
What do I need to change in order to be able to forward the button click on my directive in a directive to the controller method?
I've been working with the answers of this question but still can't make it work.
Note that, if I add
scope.clickedBtn = function() {console.log("bar");}
to the differenceViewer directive, it gets called - however I need to call the method in the controller instead.
Pass on a method from the parent to the child element and then trigger it on click. For example (pseudo code coming in )
<parent-directive>
<child-directive totrigger="parentClickCallback()"></child-directive>
</parent-directive>
then in your parent directive you set
$scope.parentClickCallback = function(){//do whatever you neeed}
and on your child in its scope binding you set
scope:{
totrigger:'&'
}
and on that child button you simply add
<button ng-click="totrigger()">ClickMe</button>
every time you click that button it will trigger parentClickCallback by reference attached to totrigger.
Why would you need to complicate your code so much I'm not really sure. If you not happy with scope binding just require controller in your directive and pass the controller bound function.

Angular directive controller scope inheritance

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

Pass ng-model as argument in directive angualjrs

I am writing a directive in AngularJs and I want to pass ng-model as an argument.
<div class="col-md-7"><time-picker></time-picker></div>
The directive is:
app.directive('timePicker', function () {
return {
restrict: 'E',
replace: true,
template: '<input type="text" class="form-control time-picker" ng-model="emp.signin">',
link: function ($scope, element, form) {
$(element).timepicker({'timeFormat': 'H:i:s'});
}
}
})
It is working fine, and here the ng-model is emp.signin. I want to be able to pass this ng-model dynamically as argument
How is this possible?
You can use
<div class="col-md-7"><time-picker model-value="emp.signin"></time-picker></div>
Angular
app.directive('timePicker', function () {
return {
restrict: 'E',
replace: true,
template: '<input type="text" class="form-control time-picker"ng-model="modelValue ">',
scope: {
modelValue : '=',
}
link: function ($scope, element, form) {
$(element).timepicker({'timeFormat': 'H:i:s'});
}
}
})
Explaination
The “=” prefix will create a two-way binding between the parent and
directive scope and it’ll always expect the attribute value to be the
model name which means you cannot provide an expression as the value
of attribute mapped to “=” prefix.
For reference: "http://www.undefinednull.com/2014/02/11/mastering-the-scope-of-a-directive-in-angularjs/"

AngularJS; Send a function from the parent into directive scope

I'm creating a reusable component/widget as a directive using a template and isolated scope. I'd like to be able to also send a callback into the directive and call it in the widget. Is this possible?
Something like...
mainView template:
<my-widget callback="someFunction"></my-widget>
directive:
return {
restrict: 'E',
scope: {
callback: '='
},
templateUrl: '/partials/widget.html',
}
And the template:
<input type="text" ng-change="callback()" />
So when the widget value is changed, it triggers the callback function that was passed in the main view
What you're looking for is &. Quoting the old angular docs: "& or &attr - provides a way to execute an expression in the context of the parent scope".
Try this as your directive code:
return {
restrict: 'E',
scope: {
callback: '&'
},
templateUrl: '/partials/widget.html',
}
You can also $watch for it in the link or controller.
.directive('myDirective', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) { {
scope.$watch(attrs.myDirective, function(value){ ... });
}
...
Turns out I needed to do as suggested and use an & rather than an =, but also this still wouldn't work until I added ng-model as well to my input:
<input type="text" ng-model="myValue" ng-change="callback()" />

Categories

Resources