Target ng-if outside controller - angularjs

I have a feedback feature on my app,
#feedback
%h3.button
%a{"ui-sref" => ".feedback", "ng-click" => "feedbackActive=!feedbackActive;"}
Feedback
#feedback-container{"ng-if" => "feedbackActive"}
%div{"ui-view" => "feedback"}
The #feedback-container has a ng-if so that the content is only loaded when needed. The %a has a ng-click that toggles between true/false for the the feedbackActive state.
This works fine. Howoever in my ui-view I load a template. In that template is a send button that has a send() function linked to the feedbackCtrl,
$scope.send = function(){
console.log ('send')
console.log ($scope.feedbackForm)
createFeedback.create({
name: $scope.feedbackForm.name,
feedback: $scope.feedbackForm.feedback
})
$scope.feedbackActive = false;
}
It runs the code fine, but doesn't give the feedbackActive the false value so nothing happens.
How do remove toggle the ng-if from outside the controller?

This is a classic scoping issue. Your controller's scope is a child of the scope of the ng-if directive. One option is to use $scope.$parent to set the variable on the parent scope.
$scope.send = function(){
console.log ('send')
console.log ($scope.feedbackForm)
createFeedback.create({
name: $scope.feedbackForm.name,
feedback: $scope.feedbackForm.feedback
})
$scope.$parent.feedbackActive = false;
}
The other option is to take advantage of prototypical inheritance. In the parent controller, initialize an object.
$scope.x = {}; //parent scope
In the view controller, set properties on the inherited object.
$scope.x.feedbackActive = false; //child scope
And of course in your HTML
<feedback-container ng-if="x.feedbackActive">

Related

ionic, pass scope variable to popover scope

I would like to pass a variable from the view scope ($scope.sort) into the popover scope.
Once set in the popover, the variable 'goes out' of it with no issue though, with code below in$scope.closeSortPopover`.
I thought the popover scope was the same as the scope of the controller it comes from.
But it seems it's not the case.
Where is the popover scope ?
If I understand correctly from here the popover scope is a child of the controller scope. So how can I access it... ?
FYI my popover is a list of <ion-radio>s offering different sorting opions for the big list in my main view.
html:
<button ng-click="openSortPopover($event, sort)">
controllers.js
$ionicPopover.fromTemplateUrl('templates/computeSortPopover.html', {
scope: $scope
}).then(function(popover) {
$scope.sortPopover = popover;
});
$scope.openSortPopover = function($event, sort) {
$scope.sortPopover.show($event);
};
$scope.closeSortPopover = function(sort) {
$scope.sortPopover.hide();
$scope.sort = sort;
};
In the controller js, you are assigning the scope of the controller to the scope of the popover. Thus all the methods in the controller scope are accessible via the popover view. In other words, both the controller view and popover view share the same scope.
In fact you might think this a violation of mvc as one controller cannot own two views, but with angular, you actually can't otherwise.
To create isolated scope, your only option is directives.
I discovered that due to javascript inheritence, the scope variable must be contained into an object to be passed to inherited scopes.
So instead of this:
$scope.sort = ....
I declared this in my controller:
$scope.data={};
$scope.data.sort = ....
and used in my html (both in the initial view and in the popover templates):
data.sort
Documented here apparently: https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance

What does passing `this` to a function inside ng-click expose?

Assume we have a button with a ng-click directive.It calls a function passing this as an argument.
Upon inspection, the type of the parameter passed is found to be an object.But neither does it have any of the element properties , nor is it a jQuery selector.
What exactly gets passed ?
ngClick and similar directives are executed in context of the current scope. So this refers scope object.
If you don't have ngRepeat, ngInclude or other directive that creates new scope then you can check in controller function and verify that this ng-click="test(this)" will pass something as $scope:
$scope.test = function(something) {
console.log(something === $scope); // => true
}
Another example. With ngRepeat you get new child scope per iteration, so in this case if you have this list:
<li ng-repeat="n in numbers">
<button ng-click="test(this)">{{n}}</button>
</li>
you will have something being a child of the main $scope:
$scope.test = function(something) {
console.log(something.$parent === $scope); // => true
};
Demo: http://plnkr.co/edit/nxxCn7SYUA4PfJpJoueu?p=info

Updating Scope from a Directive

I have defined a scope in my directive.
scope.selection = 3
When I apply the directive to an element,
<div myDirective></div>
its template would print the scope var correctly.
<span>{{selection}}</span> //prints: 3
but when I update the scope variable in the directive it does not update in the view.
element.bind("keydown", function(event){
if(event.which === 38){ //up arrow
scope.selection--;
console.log(scope.selection); //logs the updated value but view stays the same
}
}
Can I bind scopes from a directive?
EDIT:
If I view a different browser tab then go back to the app the view is then updated.

angularjs ng-class in nested directive

Tried so many different ways and still can't figure this. I have a menu with ng-class="{menuVisibleAnimation: menuOpen}" in a template in a nested directive. When I click on the button in the parent directive I want to change the value of menuOpen to true but the menu in the child directive is not updating?
http://plnkr.co/edit/nOunKkch0Gt8hjMWtruA?p=preview
The main issue in your implementation is that you want to use the the $scope to share the value of menuOpen between the parent and child directive, but your parent directive has an isolated scope :
scope: {
menuOpen: '#menuOpen'
}
You need to declare menuOpen in a scope shared by both directives, due to transclusion it has to be the parent scope of the parent directive. So, in the parent directive you should not create a new scope :
scope: false,
link: function($scope) {
$scope.menuOpen = false;
$scope.toggleMenu = function() {
$scope.menuOpen = !$scope.menuOpen;
};
}
Then, openMenu is accessible in the child directive. See it in in a fork of your Plunker.

Modify $rootscope property from different controllers

In my rootscope I have a visible property which controls the visibility of a div
app.run(function ($rootScope) {
$rootScope.visible = false;
});
Example HTML:
<section ng-controller='oneCtrl'>
<button ng-click='toggle()'>toggle</button>
<div ng-show='visible'>
<button ng-click='toggle()'>×</button>
</div>
</section>
Controller:
var oneCtrl = function($scope){
$scope.toggle = function () {
$scope.visible = !$scope.visible;
};
}
The above section works fine, the element is shown or hide without problems. Now in the same page in a different section I try to change the visible variable to show the div but it doesn't work.
<section ng-controller='otherCtrl'>
<button ng-click='showDiv()'>show</button>
</section>
Controller:
var otherCtrl = function($scope){
$scope.showDiv = function () {
$scope.visible = true;
};
}
In AngularJS, $scopes prototypically inherit from their parent scope, all the way up to $rootScope. In JavaScript, primitive types are overwritten when a child changes them. So when you set $scope.visible in one of your controllers, the property on $rootScope was never touched, but rather a new visible property was added to the current scope.
In AngularJS, model values on the scope should always "have a dot", meaning be objects instead of primitives.
However, you can also solve your case by injecting $rootScope:
var otherCtrl = function($scope, $rootScope){
$scope.showDiv = function () {
$rootScope.visible = true;
};
}
How familiar are you with the concept of $scope? It looks to me based on your code that you're maintaining two separate $scope variables called "visible" in two different scopes. Do each of your controllers have their own scopes? This is often the case, in which case you're actually editing different variables both named "visible" when you do a $scope.visible = true in different controllers.
If the visible is truly in the rootscope you can do $rootScope.visible instead of $scope.visible, but this is kind of messy.
One option is to have that "otherCtrl" code section in a directive (you should probably be doing this anyway), and then two-way-bind the directive scope to the parent scope, which you can read up on here. That way both the directive and the page controller are using the same scope object.
In order to better debug your $scope, try the Chrome plugin for Angular, called Batarang. This let's you actually traverse ALL of your scopes and see the Model laid out for you, rather than just hoping you're looking in the right place.

Resources