<!DOCTYPE html>
<html>
<head>
<link data-require="bootstrap-css@3.1.*" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
<link data-require="jqueryui@1.10.0" data-semver="1.10.0" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/css/smoothness/jquery-ui-1.10.0.custom.min.css" />
<script data-require="jquery@*" data-semver="2.1.3" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script data-require="jqueryui@1.10.0" data-semver="1.10.0" src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/jquery-ui.js"></script>
<script data-require="angular.js@*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular.js"></script>
<script data-require="ui-bootstrap@*" data-semver="0.12.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-sortable/0.13.3/sortable.min.js"></script>
<!--script src="sortable.js"></script-->
<link rel="stylesheet" href="style.css" />
<script src="app.js"></script>
<script src="directives.js"></script>
</head>
<body ng-app="app" ng-controller="MainController as mainCtrl">
<div class="content">
<h2>Sortable Widgets</h2>
<div class="row">
<div class="col-md-12">
<widget-container class="col-md-8">
</widget-container>
</div>
</div>
</div>
</body>
</html>
/* Styles go here */
body {
margin: 5px;
}
.feedback {
margin: 10px;
padding: 2px;
font: .75em Courier, sans-serif;
}
.widget-container {
margin: 5px;
padding: 2px;
border: 1px solid #ccc;
}
.widget-item {
margin: 1px;
border: 1px solid #ccc;
padding: 5px;
}
.widget-placeholder {
margin: 1px;
background-color: #fbfbfb;
height: 3px;
}
.widgets-drag-area {
margin-top: 15px;
}
.handle {
cursor: pointer;
}
#Sortable Dynamic Collection#
Custom directive with [ui-sortable](https://github.com/angular-ui/ui-sortable)
and `ng-repeat` for the items in the collection.
Author: [jasenhk](https://github.com/jasenhk)
(function() {
var app = angular.module("app", ["ui.sortable"]);
app.controller("MainController", [MainController]);
function MainController() {
}
})();
(function() {
var app = angular.module("app");
app.directive("widgetContainer", [WidgetContainer]);
function WidgetContainer() {
return {
restrict: "E",
replace: true,
templateUrl: "widgetContainer.html",
controller: "WidgetContainerController as widgetContainerCtrl",
scope: { },
link: function(scope, element, attrs, ctrl) {
}
};
}
app.controller("WidgetContainerController", ["$scope", "$timeout", "Widget", WidgetContainerController]);
function WidgetContainerController($scope, $timeout, Widget) {
var _this = this;
this.$scope = $scope;
this.$timeout = $timeout;
this.widgetFactory = Widget;
this.widgets = [];
this.index = this.widgets.length;
this.sortableOptions = {
handle: "> .handle",
update: function(event, ui) {
_this.reorder();
}
};
}
WidgetContainerController.prototype.reorder = function() {
var _this = this;
this.$timeout(function() {
for (var i = 0; i < _this.widgets.length; i++) {
_this.widgets[i].pos = i;
}
}, 0);
};
WidgetContainerController.prototype.add = function() {
var id = this.index;
var pos = this.index;
this.widgets.push(this.widgetFactory.create(id, pos));
this.index++;
console.log("add", this.widgets);
this.reorder();
};
WidgetContainerController.prototype.remove = function(widget) {
for (var i = 0; i < this.widgets.length; i++) {
if (this.widgets[i].id == widget.id) {
this.widgets.splice(i, 1);
console.log("remove", this.widgets[i], this.widgets);
this.reorder();
return;
}
}
this.reorder();
};
app.directive("widgetItem", [WidgetItem]);
function WidgetItem() {
return {
restrict: "A",
require: "^widgetContainer",
scope: {
widget: "="
},
controller: "WidgetItemController as widgetItemCtrl",
link: function(scope, element, attrs, ctrl) {
}
};
}
app.controller("WidgetItemController", ["$scope", WidgetItemController]);
function WidgetItemController($scope) {
this.widget = $scope.widget;
}
app.factory("Widget", [function() {
return Widget;
}]);
function Widget(id, pos) {
this.id = id;
this.pos = pos;
}
Widget.create = function(id, pos) {
return new Widget(id, pos);
};
})();
<div class="widget-container">
<div class="row">
<div class="col-xs-2">
<button ng-click="widgetContainerCtrl.add()" class="btn btn-sm btn-success">Add Widget</button>
</div>
<div class="col-xs-10" ng-show="widgetContainerCtrl.widgets.length > 0">
<span class="feedback">{{widgetContainerCtrl.widgets}}</span>
</div>
</div>
<div class="row" ng-show="widgetContainerCtrl.widgets.length > 0">
<div class="col-xs-offset-1 col-xs-10 widgets-drag-area">
<div ui-sortable="widgetContainerCtrl.sortableOptions" ng-model="widgetContainerCtrl.widgets">
<div widget-item ng-repeat="widget in widgetContainerCtrl.widgets" class="widget-item"
widget="widget"
data-id="{{widget.id}}" data-pos="{{widget.pos}}">
<span class="handle btn btn-xs btn-default">
<i class="glyphicon glyphicon-move"></i>
</span>
<button class="btn btn-xs btn-danger" ng-click="widgetContainerCtrl.remove(widget)">
<i class="glyphicon glyphicon-trash"></i>
</button>
<span class="label label-info">{{widget.id}}</span>
<span class="label label-warning">{{widget.pos}}</span>
<span>I'm the widget, gotta Love me!</span>
</div>
</div>
</div>
</div>
</div>