I have a directive that I have created. There is a text box and I am trying to update the count of characters in the box. First of all here is the html where my directive is declared.
<div chat-container encounter="selectedEncounter" ng-model="count"></div>
Here is my directive.
angular.module('clinicalApp').directive('chatContainer', function() {
return {
scope: {
encounter: '=',
ngModel: '='
},
controller: 'EncounterCtrl',
templateUrl: 'views/chat.container.html',
link: function(scope, elem, attrs) {
var chatbox = elem.find('textarea');
chatbox.bind('keyup',function() {
scope.updateCount();
});
}
};
});
In my template is a {{count}} that I want to be updated.
In my controller I have a function that I is called in the bind that updates the count. Here is the function in my controller.
$scope.updateCount = function() {
$scope.count = 350;
};
When this function is hit in my controller it does not update the count in my directive. How do I make this work?
Even better, how do I make the directive update the count? I thought the 2-way binding would take care of this, but it isnt. Thanks for the help.
My problem was that I was trying to update the wrong attribute in the template. If you look above I was trying to update {{count}} and I needed to update {{ngModel}}.
You need to notify angular that you updated a value:
$scope.updateCount = function() {
$scope.$apply( function() {
$scope.count = 350;
});
};
Related
I googled my problem but could not get a solution. I hope now I will definitely get the one.
I am making a directive in angular JS. for making a clickable link on repeatable text .
Lets say, I have some vouchers which i want to show using a ng-repeat and I want to make a directive which opens a modal with details of all the transactions under it.
My problem is, the ng-repeat is inserting the modal template in every loop which I think is making the DOM slow.
Directive:
.directive('viewVoucher', function($rootScope, CommonFunctionService, Server, $state, TplBaseUrl) {
return {
restrict: 'E',
scope: {
voucherNumber:'#',
voucherDate:'#',
},
link: function(scope, element, attrs) {
},
templateUrl: TplBaseUrl()+'commonTpl/voucherViewModal.php',
controller: function($scope, $element) {
$scope.title = "Angularjs Bootstrap Modal Directive Example";
$scope.showModal1 = false;
$scope.hide = function(){
$scope.showModal1 = false;
}
$scope.modalOneShown = function(){
//console.log('model one shown');
var params = {
};
Server.getInstance({apiName: 'someAPI'})
.request('functionName',params,function(data) {
if(CommonFunctionService.handleResponse(data)) {
$scope.voucherDetails = data.response;
}
});
}
$scope.modalOneHide = function(){
//console.log('model one hidden');
}
},
};
})
If I use the above directive in ng-repeat, the modal template is getting inserted everytime
Here is my directive
.directive('closeMapMessage', function($log) {
'use strict';
return function(scope, element) {
var clickingCallback = function() {
angular.element('.map').fadeOut("slow");
};
element.bind('click', clickingCallback);
};
})
How can I change a scope variable in the controller ?
<div class="msg-mobile" ng-show="showInstructionModal">
<div class="close-map-msg ok-got-it-footer" close-map-message>Ok, got it. </div>
</div>
I basically want to set my showInstructionModalfalse when my close directive is called.
From the current snippet of code, it's hard to tell why you're not using a modal solution tailored for Angular, i.e. AngularUI's modal.
However, in your current code, you're attaching a click event to the element outside of Angular's awareness. That's why clicking on the element will not have effect until the next $digest cycle has run. Also, in Agular you normally don't use directives the way you're trying to do. I would suggest updating the directive to also provide the HTML and then use the ng-clickattribute to attach the event handler via Angular.
Update your directive's code to:
.directive('closeMapMessage', function($log) {
'use strict';
return {
restrict: "AE",
link: function(scope, element) {
scope.closeModal = function() {
angular.element('.map').fadeOut("slow");
scope.showInstructionModal = false; // probably need to put this in a $timeout for example to show the fading of the element
};
},
template: '<div class="close-map-msg ok-got-it-footer" ng-click="closeModal()">Ok, got it.</div>'
};
})
And then update your HTML accordingly:
<div class="msg-mobile" ng-show="showInstructionModal">
<close-map-message></close-map-message>
</div>
You should run digest cycle manually after click event occurrence to update all scope bindings
.directive('closeMapMessage', function($log) {
'use strict';
return function(scope, element) {
var clickingCallback = function() {
angular.element('.map').fadeOut("slow");
scope.$apply();
};
element.bind('click', clickingCallback);
};
})
I am new to angular and after having researched for 2 days, I still haven't come up with a solution that will work yet.
I have a select item that will have its options updated and am also using bootstrap-select.js. I can get either or to work on their own (angular items updating dynamically as expected in a standard select list or the bootstrap-select item to work with static options). If someone could provide some guidance as to what I am doing wrong, it would be greatly appreciated! Here is my code:
HTML:
<div ng-app="app">
<div ng-controller="ctrl">
<selectpicker data-array="users" data-selected="info.selected"></selectpicker>
<button ng-click="add()">Add</button>
</div>
</div>
JS:
var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function($scope)
{
$scope.info = {selected: 1};
$scope.users=[];
$scope.users.splice(0);
$scope.users = [{name: "Bob", id: "1"},{name:"Tom", id: "2"}];
$scope.add = function () {
$scope.users.push({name: "John", id: "3"});
};
}]);
app.directive('selectpicker', function($timeout)
{
return {
restrict: 'E',
replace:true,
scope: {
selected: '=',
array: '=',
class: '='
},
template: '<select class="selectpicker" multiple data-selected-text-format="count" ng-model="currentName" ng-options="user.name for user in array">' +
'</select>',
replace:true,
link: function(scope, el, attrs) {
$timeout(function () {
scope.$watch('array', function (newVal) {
console.log(scope.array);
var select = $(el).selectpicker();
select.change(function(evt) {
var val = $(el).selectpicker('val');
$scope.selected = val;
$scope.$apply();
});
}, true);
});
}
};
});
So when I click the Add button, I can see the scope.array value
updates from the console output, but the dropdown itself won't update. I've tried piecing together solutions from similar answers but nothing has yielded results so far.
According to the documentation of Bootstrap-select, you could use refresh() method to update the UI when an underlying select tag has been changed like this:
$(el).selectpicker('refresh');
But lets look further how to improve the directive:
the element variable el is already a jQuery object, no need to wrap it again as $(el).
a $timeout is become unnecessary after the UI refresh is properly handled.
move the change event binding out of $watch, otherwise the handler will be fired multiple times per a change.
$watchCollection is enough if the options will be only add/remove i.e. an individual option will not be changed.
The final result would look like this:
link: function(scope, el, attrs) {
var select = el.selectpicker();
select.change(function (evt) {
scope.selected = el.selectpicker('val');
scope.$apply();
});
scope.$watchCollection('array', function(newVal) {
console.log(scope.array);
el.selectpicker('refresh');
});
}
Example Plunker: http://plnkr.co/edit/Kt0V0UBuHaRYMjKbI5Ov?p=preview
I'am trying to change ng-model of input inside directive by clicking on Edit anchor in directives template.
Function f() is suppose to access outer controller and bind the editableValue to name or company so i can change it through input.
Input does show persons values but it does not bind to it.
<p edit="person.name"></p>
<p edit="person.company"></p>
<input ng-model="editableValue">
main.controller('editsCtrl', function($scope){
$scope.setToEdit = function(val){
$scope.editableValue = val;
}
});
main.directive('edit', function(){
return{
template:'{{edit}}<a ng-click="f()"> Edit </a>',
restrict:'A',
scope:{
edit:"="
},
replace:false,
link: function(scope, element, attrs, ctrl) {
scope.f = function(){
scope.$parent.setToEdit(scope.edit);
}
}
}
})
Even if i do this, its not binded, just value is passed:
scope.$parent.editableValue = scope.$parent.person.name;
For newbie this becomes bit confusing, what am i missing?
Scope assignment is failing here:
scope.f = function(){
scope.$parent.setToEdit(scope.edit);
}
Because you limited scope here:
scope:{
edit:"="
},
Edit is the only scope parent will see because you have set two way databinding on it with '='
Okay, this is a convoluted question and I may be asking for a bad approach. If that's the case, please do let me know.
So I have a directive for a navigation bar. When someone clicks something, I managed to get the directive to add a class and therefore load the bar. Thanks to StackOverflow.
But now, I have a service that gets and sets values. When a value is changed in the service, I want to reflect that in a view. Is such a thing possible?
EDIT
For clarification, if I do use a $apply(function()...., how exactly do I do that? My view has something like. My view is not bound to any particular controller, or scope. Not sure if it should be. But here's a snippet of my view:
<p>
Are you sure you change that song,
<br />
{{ songs[0].title }}
</p>
Here's my directive:
angular.module('MyApp')
.directive('navbar', function () {
return {
restrict: 'A',
templateUrl : '/views/partials/nav.html',
controller: function ($scope, ModalService) {
$scope.ms = ModalService;
$scope.songs = {};
$scope.$watch('ms.songs', function(newVal, oldVal) {
if(newVal != null) {
$scope.$apply(function() {
$scope.songs = newVal;
});
}
});
},
Have you tried this?
angular.module('MyApp')
.directive('navbar', function () {
return {
restrict: 'A',
templateUrl : '/views/partials/nav.html',
controller: function ($scope, ModalService) {
$scope.songs = ModalService.songs;
}
});
I did run into a scenario recently where I had to setup a watch on a service property within a directive and the solution was to setup the watch within the link function similar to:
link: function(scope, element, attrs) {
// other link code
scope.$watch(function() { return svc.property; }, function(data) {
// do something here
});
// other link code
}