Sorry for the vague title, but I couldn't find a fitting short description.
So, I have a list of different items which I'm using ng-repeat to show. Some of them might be removed or added to that list.
I'm using ng-enter etc to animate the transition of the items entering and exiting the view. The problem is, the rest of the items, the ones that are not being added or removed, look like they hop and skip around instead of flowing naturally when items between them are being removed or added.
I made a codepen:
If you click any of the players, you remove them. Click reset to bring them back in. If you remove any of the players in the middle, you can see they jump to the left instantly after the removed item is done with its animation. I would like it to slide over to it's new position instead.
http://codepen.io/utrolig/pen/oxQVVZ
HTML:
<div ng-app="test">
<div ng-controller="AnimateController as vm">
<div class="player" ng-repeat="player in vm.items" ng-click="vm.toggleActiveState(player)" ng-if="player.active">
<div class="imgcont">
<img ng-src="{{player.img}}" />
<div class="jerseyno">
<span>#{{::player.jerseyNumber}}</span>
</div>
</div>
<div class="playername">
<span ng-bind="::player.name"></span>
</div>
</div>
<div class="resetbutton" ng-click="vm.resetActiveState(vm.players)">
<span>Reset</span>
</div>
</div>
</div>
JS:
(function(){
'use strict';
angular
.module('test', ['ngAnimate'])
.controller('AnimateController', AnimateController);
function AnimateController(){
var vm = this;
vm.toggleActiveState = toggleActiveState;
vm.resetActiveState = resetActiveState;
vm.items = [
{
name: "Pavel Bure",
active: true,
team: "Vancouver Canucks",
jerseyNumber: 10,
img: "https://nhl.bamcontent.com/images/headshots/current/168x168/8455738.jpg"
},{
name: "Wayne Gretzky",
jerseyNumber: 99,
active: true,
team: "Vancouver Canucks",
img: "https://nhl.bamcontent.com/images/headshots/current/168x168/8447400.jpg"
},{
name: "Jaromir Jagr",
jerseyNumber: 68,
active: true,
team: "Florida Panthers",
img: "https://nhl.bamcontent.com/images/headshots/current/168x168/8448208.jpg"
},{
name: "Mats Zuccarello",
jerseyNumber: 36,
active: true,
team: "New York Rangers",
img:"https://nhl.bamcontent.com/images/headshots/current/168x168/8475692.jpg"
}
];
//////////////
function toggleActiveState(item){
item.active = item.active ? false : true;
}
function resetActiveState(arr){
for (var i = 0; i < vm.items.length; i++){
vm.items[i].active = true;
}
}
}
})();
CSS:
body, html {
min-height: 100vh;
position: relative;
font-family: 'Arial', sans-serif;
background: #1d1f20;
color: rgba(255,255,255,0.7)
}
.imgcont {
border-radius: 8px;
}
.imgcont img {
border-radius: 8px;
}
.jerseyno {
position: absolute;
top: 6px;
right: 6px;
padding: 4px;
background: rgba(0,0,0,.75);
border-radius: 4px;
}
.resetbutton {
display: block;
float: left;
border-radius: 4px;
margin: 24px;
padding: 24px;
background: rgba(0,0,0,.5);
cursor: pointer;
}
.playername {
position: absolute;
bottom: 6px;
left: 6px;
background: rgba(0,0,0,.75);
padding: 4px;
border-radius: 4px;
}
.player {
float: left;
margin-right: 12px;
position: relative;
cursor: hand;
cursor: pointer;
transition: .5s all;
}
.player.ng-enter {
opacity: 0;
transform: translateY(-50%);
}
.player.ng-enter-active {
opacity: 1;
transform: translateY(0%);
}
.player.ng-leave-active {
opacity: 0;
transform: translateY(-50%);
}
Thanks!
Related
I have angular application which contains Employ model class as follow:
export interface Employee {
name: string;
type: string;
subordinates: Employee[];
}
export declare class EmployeeEntity implements Employee {
name: string;
type: string;
subordinates: EmployeeEntity[];
supervisor?: EmployeeEntity;
constructor(orgStructure: string[], supervisor?: EmployeeEntity);
}
Employee cantains property "subordinates" as array of same datatype
In participant.component.ts file, it has given values as:
export class ParticipantComponent implements OnInit {
constructor() { }
empData: Employee= {
name: "Iron Man",
type: 'CEO',
subordinates: [
{
name: "Captain America",
type: 'VP',
subordinates: [
{
name: "Hawkeye",
type: 'manager',
subordinates: []
},
{
name: "Antman",
type: 'Manager',
subordinates: []
}
]
},
{
name: "Black Widow",
type: 'VP',
subordinates: [
{
name: "Hulk",
type: 'manager',
subordinates: [
{
name: "Spiderman",
type: 'Intern',
subordinates: []
}
]
},
{
name: "Thor",
type: 'Manager',
subordinates: [
{
name: "Loki",
type: 'Team Lead',
subordinates: []
}
]
}
]
}
]
};
ngOnInit(): void {
}
}
in participant.component.html file, Im intented to print the values from model class to organization chart.
<div class = "container">
<div class="tree" *ngIf="empData">
<ul>
<li>
<a href="#"> {{empData.name}} <br/>
{{empData.type}}
</a>
<ul>
<li *ngFor="let item of empData.subordinates">
<a href="#"> {{item.name}} <br/>
{{item.type}}
</a>
<ul>
<li *ngFor="let subitem of item.subordinates">
<a href="#"> {{subitem.name}} <br/>
{{subitem.type}}
</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
now the issue is, how long do i need to keep doing *ngFor to look for values. Is there anyway which looks for the array length or some other logic as there could be unlimited number of values? pls help me out
Here is the style file incase.
* {margin: 0; padding: 0;}
.tree ul {
padding-top: 20px; position: relative;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}
.tree li {
float: left; text-align: center;
list-style-type: none;
position: relative;
padding: 20px 5px 0 5px;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}
/*We will use ::before and ::after to draw the connectors*/
.tree li::before, .tree li::after{
content: '';
position: absolute; top: 0; right: 50%;
border-top: 1px solid #ccc;
width: 50%; height: 20px;
}
.tree li::after{
right: auto; left: 50%;
border-left: 1px solid #ccc;
}
/*We need to remove left-right connectors from elements without
any siblings*/
.tree li:only-child::after, .tree li:only-child::before {
display: none;
}
/*Remove space from the top of single children*/
.tree li:only-child{ padding-top: 0;}
/*Remove left connector from first child and
right connector from last child*/
.tree li:first-child::before, .tree li:last-child::after{
border: 0 none;
}
/*Adding back the vertical connector to the last nodes*/
.tree li:last-child::before{
border-right: 1px solid #ccc;
border-radius: 0 5px 0 0;
-webkit-border-radius: 0 5px 0 0;
-moz-border-radius: 0 5px 0 0;
}
.tree li:first-child::after{
border-radius: 5px 0 0 0;
-webkit-border-radius: 5px 0 0 0;
-moz-border-radius: 5px 0 0 0;
}
/*Time to add downward connectors from parents*/
.tree ul ul::before{
content: '';
position: absolute; top: 0; left: 50%;
border-left: 1px solid #ccc;
width: 0; height: 20px;
}
.tree li a{
border: 1px solid #ccc;
padding: 5px 10px;
text-decoration: none;
color: #666;
font-family: arial, verdana, tahoma;
font-size: 11px;
display: inline-block;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}
/*Time for some hover effects*/
/*We will apply the hover effect the the lineage of the element also*/
.tree li a:hover, .tree li a:hover+ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}
/*Connector styles on hover*/
.tree li a:hover+ul li::after,
.tree li a:hover+ul li::before,
.tree li a:hover+ul::before,
.tree li a:hover+ul ul::before{
border-color: #94a0b4;
}
What you want to achieve is recursion. You have a tree-like data structure that you want to traverse when rendering.
I would recommend creating a component that can call itself recursively to render any children (subordinates).
employees.component.ts
#Component({
selector: 'employees',
templateUrl: './employees.component.html'
})
export class EmployeesComponent {
#Input() employees: Employee[];
}
<ul *ngIf="employees">
<li *ngFor="let employee of employees">
<div>{{employee.name}}</div>
<div>{{employee.type}}</div>
<div *ngIf="employee.subordinates?.length > 0">
<employees [employees]="employee.subordinates"></employees>
</div>
</li>
</ul>
The employees will render the array of Employee provided in the #Input() property. If any Employee has any subordinates, the component will then call itself with those subordinates as the #Input() property. And so on...
This will need to be kicked off from your initial data, which should also be an array.
app.component.ts
employees: Employee[] = [{
name: "Iron Man",
//... etc
}];
<employees [employees]="employees"></employees>
DEMO: https://stackblitz.com/edit/angular-nfphsl
I use this directiv : http://marceljuenemann.github.io/angular-drag-and-drop-lists/demo/#/types
I have problem to with moving cards, when i move cards higher is ok, if the cards give less the problem starts.
i did this feature :
if ($scope.movingItem.indeksList == index) {
console.log('qrwa')
$scope.lists[$scope.movingItem.indeksList].cards.splice($scope.movingItem.IndexCard +1, 1);
$scope.lists[index].cards = external[index].cards;
} else {
console.log('qrwa2')
$scope.lists[$scope.movingItem.indeksList].cards.splice($scope.movingItem.IndexCard, 1);
$scope.lists[index].cards = external[index].cards;
}
If I do the movement in the same list and i move card higher is ok then must be perform:
$scope.lists[$scope.movingItem.indeksList].cards.splice($scope.movingItem.IndexCard +1, 1);
When from up to down must be perform :
$scope.lists[$scope.movingItem.indeksList].cards.splice($scope.movingItem.IndexCard, 1);
And here is problem I cant get $index on which place I drop card to make If that I move card lower make this perform, If higer make this perform...
Here is whole project:
https://plnkr.co/edit/BVF0KxPrWiCeGDXVpQDV?p=preview
This code works:
$scope.dropCallback = function (index, item, external) {
$scope.lists[$scope.movingItem.indeksList].cards.splice($scope.movingItem.IndexCard, 1);
$scope.lists[index].cards = external[index].cards;
console.log($scope.lists[index].cards)
return item;
};
The watcher is not neccesary in this case, because you are getting informed of changes by the dropCallback function itself.
Your job is simply to remove the item at the index, like you did. Regardless of the moving direction.
EDIT
Here is the working plunker
Not sure why you need to use dropCallback just to move items around in the list. You can use dnd-moved="item.cards.splice($index, 1)" as shown in the demo.
Check out update version of your code:
angular.module("app", ["dndLists"]).controller("c1", function($scope){
$scope.title ="drag and drop";
$scope.lists = [
{
id: 2,
name: "list2",
cards: [
{ name: "card1"},
{ name: "card2"},
{ name: "card3"},
{ name: "card4"},
{ name: "card5"}
]
},
{
id: 3,
name: "list3",
cards: [
{ name: "card1"},
{ name: "card2"},
{ name: "card3"},
{ name: "card4"},
{ name: "card5"}
]
}
];
$scope.logEvent = function (indeksList, IndexCard) {
$scope.movingItem = {
indeksList: indeksList,
IndexCard: IndexCard
}
};
$scope.dropCallback = function (index, item, external) {
return item;
};
})
/* Styles go here */
.tilt {
transform: rotate(3deg);
-moz-transform: rotate(3deg);
-webkit-transform: rotate(3deg);
}
.column {
width: 170px;
float: left;
padding-bottom: 100px;
}
.portlet {
margin: 0 1em 1em 0;
padding: 0.3em;
}
.portlet-header {
padding: 0.2em 0.3em;
margin-bottom: 0.5em;
position: relative;
}
.portlet-toggle {
position: absolute;
top: 50%;
right: 0;
margin-top: -8px;
}
.portlet-content {
padding: 0.4em;
}
.portlet-placeholder {
border: 1px dotted black;
margin: 0 1em 1em 0;
height: 50px;
}
/* <BEGIN> For OS X */
*:focus {
outline: none;
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* <END> For OS X */
body {
font-family: 'Open Sans', sans-serif;
background-color: #0375AB;
}
#wrapper, #topbar-inner {
width: 95%;
margin: 0 auto;
}
#topbar {
background-color: #036492;
}
#topbar-inner {
height: 42px;
position: relative;
}
#topbar #nav {
float: left;
width: 25%;
background: yellow;
}
#topbar #logo {
width: 100%;
padding-top: 8px;
text-align: center;
}
#topbar #login {
position: absolute;
right: 0px;
bottom: 10px;
}
#topbar #logo h1 {
margin: 0;
display: inline;
font-size: 24px;
font-family: "Ubuntu", sans-serif;
color: rgba(255, 255, 255, 0.3);
}
#topbar #logo h1:hover {
color: rgba(255, 255, 255, 0.8);
cursor: pointer;
}
#wrapper {
margin-top: 30px;
}
#tasks {
width: 260px;
padding: 7px;
background-color: #E2E4E6;
border-radius: 3px;
}
#tasks h3 {
padding: 0;
margin: 0px 0px 5px 0px;
font-weight: 400;
font-size: 14px;
}
#tasks ul {
list-style-type: none;
margin: 0;
padding: 0;
}
#tasks li {
padding: 5px 8px;
margin-bottom: 4px;
background-color: #fff;
border-bottom: 1px #CCCCCC solid;
border-radius: 3px;
font-weight: 300;
}
#tasks li i {
float: right;
margin-top: 5px;
}
#tasks li i:hover {
cursor: pointer;
}
#tasks li i.fa-trash-o {
color: #888;
font-size: 14px;
}
#tasks input[type=text] {
margin: 0;
width: 244px;
padding: 5px 8px;
border-width: 0;
border-radius: 3px;
box-shadow: none;
}
.btn-login {
color: #fff;
background-color: #448DAF;
text-decoration: none;
border-radius: 3px;
padding: 5px 10px;
}
<script data-require="angular.js#1.6.5" data-semver="1.6.5" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<script data-require="angular-drag-and-drop-lists#1.2.0" data-semver="1.2.0" src="https://marceljuenemann.github.io/angular-drag-and-drop-lists/angular-drag-and-drop-lists.js"></script>
<body ng-app="app">
<div ng-controller="c1">
<ul style="list-style-type: none;">
<li ng-repeat="item in lists">
<div style="float: left; margin-left: 5px;">
<div id="tasks">
{{item.name}}
<ul dnd-list="item.cards" dnd-drop="dropCallback($index, item, lists)">
<li ng-repeat="card in item.cards"
dnd-draggable="card"
dnd-dragstart="logEvent($parent.$index, $index)"
dnd-moved="item.cards.splice($index, 1)"
dnd-selected="models.selected = item"
ng-class="{'selected': models.selected === item}"
dnd-effect-allowed="move">
{{card.name}}
</li>
</ul>
<form ng-submit="addTask(item._id, newTask, $index)">
<input type="text" ng-model="newTask" placeholder="add a new task" required />
</form>
</div>
</div>
</li>
</ul>
</div>
</body>
You can find Plunker project here.
I have two arrays whose elements I want to display as nested divs:
$scope.boxes = [{
id:1,
isLit: false,
color: 'green'
}, {
id:2,
isLit: false,
color: 'blue'
}, {
id:3,
isLit: false,
color: 'red'
}, {
id:4,
isLit: false,
color: 'yellow'
}];
$scope.images=[
{
id:1, path: './img/Baum_grün.png', color:'green'
},
{
id:2, path: './img/Baum_blau.png', color:'blue'
},
{
id:3, path: './img/Baum_rot.png', color:'red'
},
{
id:4, path: './img/Baum_gelb.png', color:'yellow'
}
]
I want to arrange them in following manner (consider those stars being images):
Right now my template looks like following:
<div class="outer-wrapper">
<div class="inner-wrapper">
<div class="box {{box.color}}" ng-repeat="box in boxes" ng-class="{'lit': box.isLit}" ng-click="boxClick(box.id)" ng-click="boxClick(box.id)" ng-audio="sounds/beep-08b.mp3" volume="0.5">
</div>
</div>
<div class="image" ng-repeat="image in images" ng-if="showImages" ng-click="imageClick(image.id, image.color)">
<img src="{{image.path}}">
</div>
</div>
And my css:
.outer-wrapper {
width: 250px;
}
.inner-wrapper {
width: 200px;
}
.box {
position: relative;
height: 50px;
width: 50px;
border: 1px solid black;
margin: 10px;
float: left;
}
.green {
background-color: green;
opacity: 0.3;
}
.blue {
background-color: blue;
opacity: 0.3;
}
.red {
background-color: red;
opacity: 0.3;
}
.yellow {
background-color: yellow;
opacity: 0.3;
}
.lit {
opacity: 1.0;
}
.image img{
height: 50px;
width: 100px;
margin-top: 45px;
float: right;
border: 0.5px solid;
margin: 10px;
}
This much code gives me following result:
What and how should I modify my css/html to achieve the desired result, it also has be responsive at least till medium sizes screens ?
It's easy if you can use flexbox - the new layout mode in CSS3. You can read more about it here: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
If you can use it, here's how you could do it:
<div id="first-container">
<div id="a">
a
</div>
<div id="b">
b
</div>
</div>
<div id="wrapper">
<div id="div-container">
<div id="x">
x
</div>
<div id="y">
y
</div>
</div>
<div id="div1-container">
<div id="z">
z
</div>
<div id="q">
q
</div>
</div>
</div>
<div id="second-container">
<div id="c">
a
</div>
<div id="d">
b
</div>
</div>
And the CSS:
#first-container, #second-container {
display: flex;
justify-content: space-between;
}
#wrapper {
display: flex;
flex-direction: column;
}
#div-container, #div1-container {
display: flex;
align-items: center;
justify-content: center;
}
#a, #c {
width: 20%;
border: solid 1px #000;
}
#b, #d {
width: 20%;
border: solid 1px #000;
}
Also, here's a working fiddle: http://jsfiddle.net/zeLh0foy/72/
I'm learning AngularJS by working through this on YouTube tutorial and I've hit a block on the 14th video with the ng-submit directive.
See code snipit below, when you fill in the form at the bottom and click submit it's supposed to add a new Ninja, but it's not working. There are no errors showing in the console. I placed a debugger breakpoint within the addNinja() function definition and it doesn't go into it when I click submit.
Any idea what I'm doing wrong?
var myNinjaApp = angular.module('myNinjaApp',[]);
myNinjaApp.controller('NinjaController', ['$scope',function($scope){
$scope.removeNinja = function(ninja){
var removeNinja = $scope.ninjas.indexOf(ninja);
$scope.ninjas.splice(removeNinja, 1);
};
$scope.addNinja = function(){
$scope.ninjas.push({
name: $scope.newninja.name,
belt: $scope.newninja.belt,
rate: parseInt($scope.newninja.rate),
available: true
});
};
// $scope.addNinja = function() {
// $scope.ninjas.push(this.newninja);
// $scope.newninja = '';
// };
$scope.ninjas = [
{
name: "Yoshi",
belt: "green",
rate: 50,
available: true
},
{
name: "Crystal",
belt: "yellow",
rate: 30,
available: true
},
{
name: "Ryu",
belt: "orange",
rate: 10,
available: false
},
{
name: "Shaun",
belt: "black",
rate: 1000,
available: true
}
];
}]);
body{
font-family: Helvetica;
margin: 0;
}
h1,h2,h3{
margin: 0;
}
.belt{
padding: 5px 10px;
border-radius: 10px;
margin-left: 5px;
color: #fff;
font-size: 15px;
text-transform: uppercase;
}
#menu-bar{
background: crimson;
color: #fff;
padding: 10px;
}
#menu-bar h1{
font-size: 24px;
font-weight: normal;
display: inline-block;
}
#menu-bar ul{
float: right;
list-style-type: none;
padding: 0;
margin: 6px 0;
}
#menu-bar li{
float: right;
margin-left: 20px;
}
#menu-bar a{
color: #fff
}
main{
background: #eee;
width: 80%;
margin: 30px auto;
border-radius: 10px;
}
.content{
padding: 20px;
}
.content button,
.content input[type="submit"]{
background: #fff;
padding: 10px;
border-radius: 10px;
cursor: pointer;
color: #777;
border: 0;
box-shadow: 2px 2px 2px rgba(20,20,20,0.1);
font-size: 16px;
}
.content button:nth-child(2){
float: right;
}
.content ul{
padding: 0;
list-style-type: none;
margin: 30px 0;
}
.content li{
padding: 15px 0;
border-top: 1px solid #e2e2e2;
color: #444;
}
.content li span{
float: right;
}
.content li h3{
display: inline-block;
font-weight: normal;
font-size: 22px;
}
.content input{
width: 90%;
padding: 10px 5%;
border-radius: 10px;
border: 2px solid #ddd;
margin: 10px 0;
}
.content input[type="submit"]:last-child{
width: 150px;
display: block;
margin: 15px auto;
}
.remove{
float: right;
padding: 5px;
background: #fff;
width: 18px;
text-align: center;
border-radius: 20px;
color: crimson;
cursor: pointer;
margin-left: 10px;
}
<!DOCTYPE html>
<html lang="en" ng-app="myNinjaApp">
<head>
<title>TheNetNinja Angular Playlist</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body>
<div class="content">
<div ng-controller="NinjaController">
<button ng-click="order = 'name'">Order by Name</button>
<button ng-click="order = 'belt'">Order by Belt</button>
<input type="text" ng-model="search" placeholder="Search for a ninja">
<ul>
<li ng-repeat="ninja in ninjas | orderBy: order | filter: search" ng-show="ninja.available">
<h3>{{ninja.name}} - {{ninja.rate | currency: '£'}}</h3>
<div class="remove" ng-click="removeNinja(ninja)">x</div>
<span class="belt" style="background: {{ninja.belt}}">{{ninja.belt}} belt</span>
</li>
</ul>
</div>
<form ng-submit="addNinja()">
<input type="text" placeholder="name" ng-model="newninja.name" />
<input type="text" placeholder="belt" ng-model="newninja.belt" />
<input type="text" placeholder="rate" ng-model="newninja.rate" />
<input type="submit" value="Add new ninja">
</form>
<p>{{newninja}}</p>
</div>
</body>
</html>
You have a div in the wrong place - move </div> above <form ng-submit="addNinja()"> to after <p>{{newninja}}</p>
bascially the ng-submit is not within the ninjacontroller div
see - https://plnkr.co/edit/pPucxMw0Yjr9OZoxl0vy?p=preview for a working version
myNinjaApp.controller('NinjaController', ['$scope', '$http', '$log', function ($scope, $http, $log) {
$http({
url: "data/ninjas.json",
method: "GET"
}).then(function (resp) {
//$log.log(resp.data);
$scope.ninjas = resp;
}, function (resp) {
$log.error("ERROR Occurred");
//debugger;
});
$scope.removeNinja = function (ninja) {
var removeNinja = $scope.ninjas.indexOf(ninja);
$scope.ninjas.splice(removeNinja, 1);
}
$scope.addNinja = function () {
$scope.ninjas.push({
name: $scope.newninja.name,
belt: $scope.newninja.belt,
rate: parseInt($scope.newninja.rate),
available: true
});
$scope.newninja.name = "";
$scope.newninja.belt = "";
$scope.newninja.rate = "";
};
$scope.removeAll = function () {
$scope.ninjas = [];
};
$scope.sort = function (keyname) {
$scope.sortKey = keyname;
$scope.reverse = !$scope.reverse;
}
}]);
I have a left-hand side (lhs) list box and right-hand side (rhs) list box I want to be able to select items in the lhs listbox and add one or all of them to the rhs listbox. Then I'd also like a remove one or all from the rhs returning them to the lhs. How would I accomplish this? So far, I can only manage getting the index value of the lhs box to the right but it won't take the actual item name for some reason. This is the code that does that:
private void SelectOne_Click(object sender, RoutedEventArgs e)
{
listBoxFin.ItemsSource = listBoxStart.SelectedIndex.ToString();
}
Hi this is not the final solution but this will help you lot.
Working DEMO.
HTML
<div class="wrapper">
<div class="selectbox alignleft">
<ul id="selection" class="cf">
<li>One <span class="desc">Description</span></li>
<li>...</li>
<li>...</li>
</ul>
</div>
<div class="movebutton alignleft">
<input class="button mover" value=">>" type="button" />
</div>
<div id="moving" class="movebox alignleft">
<ul class="cf">
<li>One <span class="desc">Description</span>
</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
</ul>
</div>
<div class="alignleft">
<input class="button" id="move-up" type="button" value="Up" />
<input class="button" id="move-down" type="button" value="Down" />
</div>
CSS
.cf:before, .cf:after {
content:"";
display: table;
}
.cf:after {
clear: both;
}
/* For IE 6/7 (trigger hasLayout) */
.cf {
zoom: 1;
}
/* general purpose classes */
.nodisplay {
display: none;
}
.nodisplay_strict {
display: none !important;
}
.alignleft {
float: left;
}
.alignright {
float: right;
}
.button {
cursor: pointer;
background: #eee;
border: 0;
min-width: 116px;
padding: 5px 0;
margin-bottom: 2px;
display: block;
}
body {
padding: 25px;
font-family:Verdana, Geneva, sans-serif;
font-size: 12px;
}
li {
display: block;
cursor: pointer;
padding: 5px;
font-weight: bold;
position: relative;
border-bottom: 1px solid #fff;
}
li.active {
background: #000;
color: #fff;
}
.wrapper {
width: 960px;
margin: 0 auto;
}
.selectbox {
border: 1px solid;
width: 150px;
min-height: 199px;
max-height: 199px;
overflow-y: auto;
position: relative;
}
.movebox {
border: 1px solid;
width: 200px;
min-height: 199px;
max-height: 199px;
overflow-y: auto;
position:relative;
margin-left: 10px;
margin-right: 10px;
}
span.desc {
display: block;
padding-top: 5px;
color: #7a7a7a;
font-weight: normal;
font-style: italic;
}
li.active span.desc {
color: #ccc;
}
.movebox .delete, .movebox .unmoved {
display: inline-block;
position: absolute;
right: 5px;
top: 5px;
z-index: 999;
background:url(icon-close.png) no-repeat 0 0 red;
width: 10px;
height: 10px;
text-indent: -99999px;
}
.movebutton {
margin-left: 10px;
}
.movebutton .mover {
background: url(icon_right.png) no-repeat 0 0 #eee;
height: 48px;
margin: 65px auto 0;
min-width: 0;
text-align: center;
width: 48px;
}
.moved {
background: #d9fffe;
}
#move-up {
background: url("icon_up.png") no-repeat 0 0 #eee;
height: 48px;
margin: 0px auto 0;
min-width: 0;
text-align: center;
width: 48px;
}
#move-down {
background: url("icon_down.png") no-repeat 0 0 #eee;
height: 48px;
margin: 15px auto 0;
min-width: 0;
text-align: center;
width: 48px;
}
JavaScript
// JavaScript Document
$(document).ready(function (e) {
$('.selectbox li, .movebox li').click(function () {
$(this).addClass('active').siblings().removeClass('active');
});
$('.mover').click(function () {
$('.selectbox li.active').addClass('moved').prependTo('.movebox ul').prepend('<span class="delete alignright" onclick="moveToLHS(this);">DELETE</span>');
});
$('.mover').click(function () {
$('.selectbox li.active').addClass('moved');
$('.movebox li.active').removeClass('active');
setTimeout(function () {
$('.movebox li').removeClass('moved');
}, 1500);
});
$('.movebox ul li').each(function () {
$(this).prepend('<span class="unmoved alignright" onclick="deleteFromRHS(this);">DELETE</span>');
});
$("#move-up").click(moveUp);
$("#move-down").click(moveDown);
$("#reset-list").click(resetList);
});
//DELETE
function moveToLHS(t) {
$(t).parent().remove().prependTo('.selectbox ul');
$('.selectbox li').click(function () {
$(this).addClass('active').siblings().removeClass('active');
});
//deleting span
$('.selectbox ul li .delete').each(function () {
$(this).remove();
});
}
function deleteFromRHS(d) {
$(d).parent().remove();
}
// LI Up Down
function moveUp() {
$("#moving li.active").each(function () {
var listItem = $(this);
var listItemPosition = $("#moving li").index(listItem) + 1;
if (listItemPosition == 1) return false;
listItem.insertBefore(listItem.prev());
});
}
function moveDown() {
var itemsCount = $("#moving li").length;
$($("#moving li.active").get().reverse()).each(function () {
var listItem = $(this);
var listItemPosition = $("#moving li").index(listItem) + 1;
if (listItemPosition == itemsCount) return false;
listItem.insertAfter(listItem.next());
});
}
function resetList() {
$("#moving").html(originalItems);
}
Working DEMO
As H.B. noted, there are many ways this could be accomplished. Probably the most widely acclaimed architecture for WPF is MVVM, so I'll try to outline a solution with respect to my understanding of that architecture.
The ViewModel will expose a few different properties: LHSList, LHSSelectedItem, RHSList, RHSSelectedItem (collections are ObservableCollections here) as well as a few commands - MoveLHSSelectedToRHS, MoveLHSToRHS, MoveRHSSelectedToRHS, MoveRHSToLHS.
The lists are simple bindings to the ListViews in the View, and the SelectedItem's of those ListViews are also bound accordingly. The commands simply operate on the lists and the selected items. For example, MoveLHSSelectedToRHS would be a command with an action something like:
public void OnMoveLHSSelectedToRHS()
{
if(LHSSelectedItem==null)
return;
RHSList.Add(LHSSelectedItem);
LHSList.Remove(LHSSelectedItem);
LHSSelectedItem=null;
}
Unfortunately, it looks like you are using code behind at the moment. If you are not familiar with MVVM, I'd suggest looking into Josh Smith's WPF articles - they're a great place to start!