Is it possible to chain instructions in an ng-click? - angularjs

I've got a couple of sliders I want to pick from a menu.
As a consequence, I need to both pick the right slider and reset the first slide to 0.
I have a slide model I set to 0 fro the ng-click just before opening the popup, but, unfortunately, slide is not reset to 0.
Any idea?
PS: I don't want to move the slide variable to the scope of the controller.
<div ng-init="slide = 0"></div>
<div
ng-repeat="s in sliders"
style="left:{{s.center.x - 70}}px; top:{{s.center.y}}px"
ng-click="slide = 0; openPopover('#slides-{{s.name}}')"
>
{{s.displayName}}
</div>

As long as it's a valid angularjs/js expression it will work
http://plnkr.co/edit/wta6GcVZHVccVbCf08IT?p=preview
<body ng-controller="MainCtrl">
<p ng-click="set = 'Cowa'; to = 'bunga!'; popup('test')">Hello {{name}}!{{set}}{{to}}</p>
</body>

As ng-repeat creates it's own scope, your current code will set slide to 0 inside these scopes. A quick (and maybe dirty) way is to use $parent to directly reference the parent-scope. E.g:
ng-click="$parent.slide = 0; openPopover('#slides-{{s.name}}')"

Related

Element not updated with calculated value in Angular.js v 1.0.7

When I load a page to display items prices, before the prices are calculated in the controller the page displays "null" in the price for a while (maybe 1 sec). How can I avoid this? I thought this is the purpose of ng-init, is it right?
When I use it, I get my items initialized to 0. This is ok. However, when the value is calculated the price is not updated.
Example:
<div class="text-right custom_block_field" ng-show="booking.duration == 0" ng-init="itemSelected.convertedPrice = 0">{{(itemSelected.convertedPrice)}}</div>
ng-init is not for that, it is basically used to call a method or some initialization of the values
<div class="text-right custom_block_field"
ng-show="booking.duration == 0"
ng-bind="itemSelected.convertedPrice"></div>
Or use the ng-cloak with parent element
ng-cloack is the best way. It'll mask a value until it's ready.
<div ng-cloak>
//whatever your app code is
</div>

Scope changes after ng-switch

I have a switch that changes the value of a variable called p.
<div ng-switch on="p">
<div ng-switch-when="true">
/*...show nodes and ability to add node*/
</div>
<div ng-switch-when="false">
/*for now show nothing*/
</div>
</div>
In my controller:
$scope.nodes=[{node1},{node2},{node3}];
function to add a node
$scope.$watch('nodes', function(nodes) {
console.log(nodes);
console.log("================");
},true);
PROBLEM: when i print $scope nodes in the above all the new nodes are shown. If I switch OFF and ON (p=false and then p=true) I have the initial $scope.nodes. Why on earth are my nodes reset on switch?
See this example: plunker
EDIT: ng-switch worked with no scope change if I didn't have a directive but reinitialized my scope when I used a directive inside it. Although I haven't understood exactly why I dropped ng-switch and used ng-show instead.
It would help to see the controller and on which level it is initialized. The ngSwitch will not just hide the content - it will remove and add the html and initialize the controllers and directives each time a switch is made. Probably the nodes get initialized there as well.

How to set a boolean flag to collapse/expand a row with ng-repeat

I have this plunker code.
What I'm trying to do, is to display the gray box one time per row.
To achieve this, I thought to modify the partition filter in order to return a JSON to add it a new property by row to know if the gray box is expanded or not.
But, I could Not successfully return a JSON.
Do you know how to modify the filter to return a JSON or a better way to show the gray box by row?
Related questions:
Push down a series of divs when another div is shown
Update 1
The issue could be easily resolved by using the correct scope for the ng-repeat for the row without modifying the filter, thanks to #m59.
http://plnkr.co/edit/eEMfI1lv6z1MlG7sND6g?p=preview
Update 2
Live Demo
If I try to modify the item, it seems the ng-repeat would be called again losing the props values.
<div ng-repeat="friendRow in friends | partition:2"
ng-init="props = {}">
<div ng-repeat="item in friendRow"
ng-click="collapse(item)"
ng-class="{myArrow: showArrow}">
{{item.name}} {{item.age}} years old.
<div>{{item.name}}</div>
</div>
<div collapse="!props.isExpanded">
some content
<br/>
<input type="text" ng-model="currentItem.name">
</div>
</div>
js
$scope.collapse = function(item){
this.props.isExpanded = !this.props.isExpanded;
this.showArrow = !this.showArrow;
$scope.currentItem = item;
};
This causes the gray box to collapse each time the item is modified. Any clue?
I've updated my code/answer regarding partitioning data. It's important to fully understand all of that before deciding on an approach to your project.
The problem you have in your plnkr demo is that you're modifying the parent $scope and not the scope of the ng-repeat for that row.
Just set a flag on the row and toggle it when clicked:
Live Demo
<div
class="row"
ng-repeat="friendRow in friends | partition:2"
ng-init="isExpanded = false"
ng-click="isExpanded = !isExpanded"
>
<div ng-repeat="item in friendRow">
{{item.name}} {{item.age}} years old.
</div>
<div collapse="!isExpanded">
some content
</div>
</div>
To access the correct scope within a function in the controller, you can use the this keyword instead of $scope. this will refer to the scope the function is called from, whereas $scope refers to the scope attached to the element with ng-controller (a parent of the ng-repeat scopes you want to target).
<div
class="row"
ng-repeat="friendRow in friends | partition:2"
ng-click="collapse()"
>
JS:
$scope.collapse = function() {
this.isExpanded = !this.isExpanded;
};
If you want to keep the ng-click directive on the item element instead of putting it on the row element as I have done, then you're dealing with another child scope because of that inner ng-repeat. Therefore, you will need to follow the "dot" rule so that the child scope can update the parent scope where the collapse directive is. This means you need to nest isExpanded in an object. In this example, I use ng-init="props = {}", and then use props.isExpanded. The dot rule works because the children share the same object reference to props, so the properties are shared rather than just copied, just like in normal JavaScript object references.
Live Demo
<div
class="row"
ng-repeat="friendRow in friends | partition:2"
ng-init="props = {}"
>
<div ng-repeat="item in friendRow" ng-click="collapse()">
{{item.name}} {{item.age}} years old.
</div>
<div collapse="!props.isExpanded">
some content
</div>
</div>
JS:
$scope.collapse = function(){
this.props.isExpanded = !this.props.isExpanded;
};
Update
We keep going through more and more issues with your project. You really just need to experiment/research and understand everything that's going on on a deeper level, or it will just be one question after another. I'll give it one last effort to get you on the right track, but you need to try in the basic concepts and go from there.
You could get past the issue of props reinitializing by putting $scope.expandedStates and then passing the $index of the current ng-repeat to your function (or just using it in the view) and setting a property of expandedStates like $scope.expandedStates[$index] = !$scope.expandedStates[$index]. With the nested ng-repeat as it is, you'll need to do $parent.$index so that you're associating the state with the row rather than the item.
However, you'll then have another problem with the filter: Using my old partition code, the inputs inside the partitions are going to lose focus every time you type a character. Using the new code, the view updates, but the underlying model will not. You could use the partition filter from this answer to solve this, but from my understanding of that code, it could have some unexpected behavior down the road and it also requires passing in this as an argument to the filter. I don't recommend you do this.
Filters are meant to be idempotent, so stabilizing them via some kind of memoization is technically a hack. Some argue you should never do this at all, but I think it's fine. However, you definitely should ONLY do this when it is for display purposes and not for user input! Because you are accepting user input within the partitioned view, I suggest partitioning the data in the controller, then joining it back together either with a watch (continuous) or when you need to submit it.
$scope.partitionedFriends = partitionFilter($scope.friends, 2);
$scope.$watch('partitionedFriends', function(val) {
$scope.friends = [].concat.apply([], val);
}, true); // deep watch

Get data inside an ng-repeat from an directive outside of it

I'm developing a mobile application using Ionic Framework based an AngularJS.
On one directive I'm looping over a JSON Array with ng-repeat applying a condition with ng-if, see below:
<ion-content class="has-header has-subheader" >
<ion-slide-box">
<ion-slide
ng-if="invocation.title_id == titleid"
ng-repeat="invocation in invocations" >
<h3>{{invocation.id}}</h3>
<div ><h1>{{invocation.invocation_frensh }}</h1></div>
<div ><h1>{{invocation.invocation_ar}}</h1></div>
<div ><h1>{{invocation.invocation_franko}}</h1></div>
<div ><h1>{{invocation.comments_fr}}</h1></div>
<div ><h1>{{invocation.comments_ar}}</h1></div>
</content>
</ion-slide>
</ion-slide-box>
<p>{{invocation.id}}</p>
</ion-content>
The point is that on the last p nothing is shown.
I understand that the $scope is not the same but on the last "p" or any other component outside the ng-repeat I need to have the same data in order to interact with it.
For exemple I want to add a button on a footer that gets the "{{invocation.id}}". If invocation.id equals 3 inside the ng-repeat "h3" I want to have it equals 3 in the "p"
How can i do it ?
Thanks for you help
Edit: In fact I want invocations[index].id in the 'p' outside of the loop, where index equals the displayed slide.
the invocation variable dies when the ng-repeat ends, if you need to use it again, you will need another ng-repeat
Assuming that you want to show only one slide at a time, you could do it without ng-if, and use filter instead.
<ion-slide ng-repeat="invocation in displayedInvocations = (invocations | filter:{title_id: title_id}:true)">
and then at outside:
<p>{{displayedInvocations[0].id}}</p>
Hope this helps.

Can an Angular ng-mousover event trigger ng-style on multiple elements?

I'm currently learning Angular and I have a question.
I have two divs that change their background color on triggering the ng-mouseover directive. here is a little snippet of the two divs.
<div id="mid-left" class="col-lg-4">
<div class="row left-section" ng-repeat="variance in variances.variance_data" ng-style="background" ng-mouseover="background = setColor(variance)" ng-mouseleave="background = {}">
</div>
<div id="mid-right" class="col-lg-4">
<div class="row right-section" ng-repeat="variance in variances.variance_data" ng-style="background" ng-mouseover="background = setColor(variance)" ng-mouseleave="background = {}">
</div>
I assumed that the background variable I declared in the directives would be added to the existing $scope.
With the two divs being bound to the 'same variable' (in my mind) I assumed they would both change on when either ng-mouseover event was triggered.
Any and all help is highly appreciated.
Instead of background = setColor(variance), you should be defining a background variable in your local scope, and creating a function on the scope called setColor that alters the local scope background value. You'd then want to build a function to clear that value, as opposed to setting it to an empty object within your view.
ng-style takes..
Expression which evals to an object whose keys are CSS style names and
values are corresponding values for those CSS keys
I think it's impossible to say why it doesn't work without seeing what's returned from setColor(variance)

Resources