angularjs: $scope update when I change a select with jQuery - angularjs

I'm using a jQuery plugin to 'customize' my selects.
This plugin fires the change event of the original select when some option is selected.
The problem is that my scope doesn't change.
Here you can see a quick example... changing the select the scope changes. clicking the buttons the select changes but not the scope.
http://plnkr.co/edit/pYzqeL6jrQdTNkqwF1HG?p=preview
What am I missing?

You need to access the scope of the dropdown and then apply it as shown below:
$('button').on('click', function(){
var newVal = $(this).data('val');
$('select').val(newVal).change();
var scope = angular.element($("select")).scope();
scope.$apply(function(){
scope.selectValue = newVal;
});
});

When you click the button, angular goes out of its scope and uses jquery to manipulate the data/to perform some action, so we need to exlicitly call $scope.$apply() to reflect the changes back into the scope of the controller. And change your controller to this:
app.controller('AppCtrl', function($scope) {
$('button').on('click', function(){
$scope.selectValue=$(this).data('val');
$scope.$apply();
});
}
By the way you can use jquery event inside the angular..

Ideally in angularJS, controller should not update DOM reference directly. If you want to achieve same thing, you should expose one method over $scope and use "ng-click" directive.
If you want to achieve same using jQuery, it should go into directive as
$scope.$apply()
to update the scope.

In your jQuery put auto trigger e.g
$('#input').click(function(){
$('#input').val('1');
$('#input').trigger('input'); //add this line this will bind $scope Variable
});

It's best not to mix DOM manipulation with Angular. Try the following for your button HTML:
<button class="setVal" ng-click="selectValue=1">Set 1</button>
<button class="setVal" ng-click="selectValue=2">Set 2</button>
<button class="setVal" ng-click="selectValue=3">Set 3</button>
I tried the above in your Plunker and it worked.

Related

Angular checkbox update not running a full digest onclick to display template

How can I make checkbox run a full digest onclick, instead of onblur?
My problem is, the checkbox click only runs the local scope for the directive it is inside. I also have other directives that need to update onclick, instead of onblur.
I tried using ng-click and $scope.$apply() but I was getting $rootScope digest errors. After looking around a bit more I added $timeout around the $scope.$apply(). This fixed all my issues.
scope.ngclickApply = function(){
$timeout(function(){
scope.$apply();
},0,false)
}
and in the html
<label ng-click="ngClickApply()">
<input type="checkbox">{{label}}
</label>

Changing $scope from inside $rootScope is not getting reflected

I am trying to show one button as in this Plunker
<div ng-show="showbtn"><button class="fix btn btn-success" ng-click="top()">To the top</button></div>
On scroll event, I have made $rootScope.$emit call and it is getting triggered too, but not sure why the $scope value is not getting changed inside the mainCtrl controller $scope. Is $scope inside $rootScope is different ?
The event handler (the function passed to $rootScope.$on) runs outside of Angular's normal digest cycle so you need to tell the parent scope that something has changed. You can use $apply to do so:
$rootScope.$on('scrolled',function(event,data){
$scope.$apply(function () {
$scope.showbtn = data.message;
});
});
Here's an updated Plunker.

Event onclick in my controller

I wrote thi code in my controllers:
$('#categoryId').on('click', function(event){
$scope.items = $scope.getUpdatedItems ();
console.log('Items ',$scope.items );
});
In my directives I have this:
....
scope.$watch('items', function(items){
console.log('Directives - Items ',items );
....
The problem is that I never enter in the $watch declared in my directives.
Somebody can help me..
Thanks
You shouldn't mixed up jQuery with AngularJS that will mess up with the digest cycle on angular. Angular did provided its own directive to handle such activity like in your case you could us ng-click directive, this will call the mentioned function inside ng-click attribute value on click on that element.
Markup
<button type="categoryId" ng-click="updateAllItems()"></button>
Code
$scope.updateAllItems = function(){
$scope.items = $scope.getUpdatedItems ();
console.log('Items ',$scope.items );
});
Above code will call updateAllItems function which resides inside controller & then $scope.items will get updated. And then you watch inside directive will get call.

Angularjs destroy is not working

http://plnkr.co/edit/UfQJU661pQR0DMY3c61t?p=preview
I got above code from AngularJs site and only thing I have added a button to delete a Div where we have controller but after delete no destroy method called as I have put alert in Directive and Controller.
element.on('$destroy', function() {
alert('destroy directive interval');
$interval.cancel(stopTime);
});
and
$scope.$on('$destroy', function() {
alert('destroy controller interval');
// Make sure that the interval is destroyed too
$scope.stopFight();
});
please suggest.
Thanks
The main thing to be noticed
When element.remove() is executed that element and all of its children will be removed from the DOM together will all event handlers attached via for example element.on.
It will not destroy the $scope associated with the element.
So you need to manually trigger scope.$destroy();
First get the scope of element:-
var scope = angular.element(document.getElementById("mainDiv")).scope();
Second remove the element from dom:-
$('#mainDiv').remove();
Third destroy scope manually:-
scope.$destroy();
Plunker
You're doing it outside of angular's context.
<button id="btn" onclick="DeleteMainDiv()">DeleteDiv</button>
So in your DeleteMainDiv() function
function DeleteMainDiv() {
alert('Controller div going to remove');
//debugger;
var scope = angular.element(document.getElementById("mainDiv")).scope();
$('#mainDiv').remove();
scope.$destroy();
}
This will trigger the destroy functionality.
But I don't see a need of it. Angular will automatically run the $destroy event handler when the route changes or directive no longer required.
DEMO

How can I call a method on a custom directive's isolated scope from within a transcluded controller in Angular.js

I created a directive called dt-modal under the dt module. In my main app's module called demo, I use this dt-modal which has an isolated scope. I created this directive such that the HTML form written within the directive is transcluded since I want to reuse this modal for many different forms.
<dt-modal>
<form ng-controller="ReviewFormController"
name="reviewForm"
novalidate
ng-submit="reviewForm.$valid && submitReview(review)">
<!-- form contents here -->
</form>
</dt-modal>
This transcluded form has a custom controller called ReviewFormController that listens for the submit event. How can I call the close() method on the dt-modal's scope from within submitReview() in ReviewFormController?
Here is a JSBin. If you hit ESC, you can see close() in the directive run.
http://jsbin.com/cukanole/1/edit
If this isn't possible, is there a better design for this directive?
Thanks in advance!
Since you are using an isolated scope, you could pass a control object to the directive...
<dt-modal id="review-form-modal" api="modal.api">
and add the close method to it via two-way binding:
scope: {
api: '='
},
link: function($scope, $el, attrs) {
$scope.api = {
close: function() {
$el.css({
display: 'none'
})
}
}
...
Then ng-click can use the control object to call close:
<button type="submit" ng-click="modal.api.close()">Submit</button>
If you want to try this code, here it is on Plunker.
My recommendation is to use $emit to trigger the event from the controller and use $on on the directly.
Controller
scope.$emit("ValueChanged", value);
In the directive the event will be captured using $on like:
$scope.$on("ValueChanged", function(event, ars){
... //your event has been triggered.
});
Important:
Directives should be always independent components, if inside the directive there is a call to a method from a controller(outside the directive) this will create a dependency between my directive and the controller and of course this will force one not being able to exist without the other.
If I would have to apply a design principle to a directive it will be the S in SOLID, Single responsibility principle. Directives should be able to encapsulate and work independently.

Resources