Animate element moving between lists - angularjs

Using AngularJS, I would like to animate an element being added to one list from another, as in a clone of the element should appear to move in the page from the menu of items, and be added to the target list.
<ul class="list">
<li ng-click="choose(item)" ng-repeat="item in originItems">{{item.name}}</li>
</ul>
<ul class="list">
<li ng-repeat="item in targetItems track by $index">{{item.name}}</li>
</ul>
Where the function that adds the items does a simple push
$scope.choose = function(item) {
$scope.targetItems.push(item);
}
You can see this in action (with no animation) at this Plunker
I've considered custom directives and events, but not really got anywhere. What's a good structure of directives and/or events to allow this movement animation be achieved, keeping this a separate from the business of adding to a list as possible?
Note: my exact situation in terms of business logic and animation is a bit different, but I'm hoping the solution to this is flexible enough to allow some changes/additions to what happens in the menu, during the "move" animation, and what happens in the target list.

Demo http://plnkr.co/edit/XYnf7U?p=preview
I removed list style to ensure proper position of list item while moving. If you have to enable list style, you have to consider that.
The demo works by: when user add an item, it get the position of original and final items, and apply a jquery animation to the cloned list item between those two positions.
Use $event.target to identify original item.

Related

angular add property to model

I have an angular service that returns a list of items from the database.
I display those items through an ng-repeat. I'd like to hide/show each one of them using the ng-show.
Is it a good practice to add a "display" property directly on my items to show or hide them in the UI?
Edit: If someone could point me to an article explaining that orientation (can't seem to find any).
Yes. This is the right choice. It enables your model to control how items are viewed according to a separately controlled logic. This makes your application scalabale too.
A filter is a better choice in further modeling your logic.
As suggested by other answers, filter is the better choice for your case. Add a property display and then filter based on that property.
<div ng-repeat="item in dataFromServer | filter:{ display: true }">
{{item.name}}
</div>
I have used underscore to create a new property for each object
https://jsfiddle.net/k8u3c8t7/

How to preserve DOM elements when using ng-repeat with filter?

I have an ng-repeat with a filter. When some items are filtered out by the filter and then they are restored after another filter change there are new DOM elements created for these items. If there was any DOM manipulation on the item it gets lost after item is hidden and restored with filter.
Is there a way to keep the DOM elements, even when item is removed by filter?
I tried using track by, but it doesn't help.
Here is a fiddle that recreates the problem.
Steps to recreate:
Click the button to apply colors to DOM elements
Type something in the filter input (for example 'ap') to hide some of the elements
Remove the filter. The restored elements lost their style.
Angualr is dynamically adding and removing those templates. By template I mean whatever tag(s) are inside your ng-repeat. There is no way to preserve that in an ng-repeat. Instead, if you want this color change to be preserved, it needs to be a part of the model you are ng-repeat ing over. Does that make sense?
Add the color directly to the template style="color: {{fruit.color}}"
See this for what I am talking about
http://jsfiddle.net/nferjvsp/1/

Preserve the state of a directive within ng-repeat

Let's say I have something like this:
<div ng-repeat="item in list">
<div change-color>Some content</div>
</div>
Where the directive "changeColor" can change the background color of the div by clicking it.
If I now change the content of my list, say by a HTTP-request which overwrites the whole list:
$scope.list = newList;
My "changeColor" directive "reloads", since the divs will be repopulated, is it possbile, by some angular-way to preserve the state of the div (by which the directive has changed it) or do I need to do it manually?
P.S.
This would be really useful since in my situation I have a huge list of items where the user wants to interact with each item in a way like above, but the list is overwritten each 30 seconds and that clears all the "changes" to it's pristine state.

In AngularJS, what is the correct way to filter an array based on odd or even $index property?

I want to filter an array based on even and odd $index property and I want to add odd elements in a separate div and even elements in another div, I could easily do this in JavaScript or jQuery, but I wanted to know the correct way to implement the same in AngularJS.
This is what I've done so far:
<div ng-app>
<div ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
<div class="row" ng-repeat="name in names">
<div class="col-xs-6" ng-show="(($index + 1)%2) == 0">{{name}}</div>
<div class="col-xs-6" >{{name}}</div>
</div>
</div>
</div>
It shows empty spaces in place of odd elements in first case, and when I add the odd expression for second div, the elements in the second div disappear and appear in first div. Here is the fiddle for the same issue.
Please advise.
EDIT:
I have got what I wanted, I split the main array into two different arrays odd and even array; this fiddle may be useful for people who stumble upon the same issue in the future.
Since Angular 1.2.0-rc1, ngRepeat exposes the $odd and $even properties on the local scope. You can simply use an ngSwitch based on one of this properties:
<div ng-repeat="item in itemsList" ng-switch="$even">
<div ng-switch-when="true">{{item}} is even</div>
<div ng-switch-default>{{item}} is odd</div>
</div>
Notice that if you just want to change the class based on the parity, ngClassOdd and ngClassEven are available since 1.0.0:
<div ng-repeat="item in itemsList" ng-class-even="'even'" ng-class-odd="'odd'">
{{item}}
</div>
All-in-one Fiddle
I think you're going to have some trouble with what you're looking to do, due to the way ng-repeat works. It generates a new scope for each iteration of the repeat. So you'll end up with two divs each time through the loop, one visible and one hidden.
To explain the weird behavior you've been seeing:
In your first case, the loop is alternating between showing two divs and showing one div. In a row that displays only one div, it understandably looks like a blank was inserted in the second column.
In the second case, the ng-repeat loop alternates between showing the first div and the second one. Without some CSS styling to show the difference, it looks like one div. You can make it pop by adding a style such as text-info to one of the divs.
I hope that explains what's going on behind the scenes, but the better question is... what are you trying to accomplish with the two divs?
Update: Since it looks like your goal is to take that array and pump it out into a 2-column layout, you can probably do away with your row div and your 2 column divs. Instead, try repeating a single 6-width column div. It'll handle the row wrapping for you every other column. You can use odd and even styling as #Blackhole pointed out if you want to differentiate the divs. I've got an example fiddle set up here that may be of use.

ng-repeat: adding a new element with an effect

Currently I am using ng-repeat to show a division.
<div class="something" ng-repeat="item in items">{{item.name}}</div>
In my controller the moment I add one more item to items it shows in my page. But it just displays the new content. What I want is to show an effect while its added like the new div should slide down while being added to the page. How I can I achieve it?
Try adding a ngAnimate attribute with animation values. You can find more information here
http://www.yearofmoo.com/2013/04/animation-in-angularjs.html#animating-ng-repeat

Resources