Angular Sortable Dynamic Collection

Here’s an example of a sortable (ui-sortable) on a dynamic collection that I’ve worked out. I’ve wrapped this in a custom directive for a collection of widgets that can be re-ordered.

See the Plnkr working example.

Screen Shot

It uses Angular, Bootstrap and ui-sortable. Unfortunately, there is a dependency on jQuery UI Sortable but I don’t see any problems with this example.

Usage

Custom directive


<widget-container class="widget-container"></widget-container>

Directive Template

This is the basic template with the important bits (most of the styling removed). There’s a second directive widget-item embedded to help with the child (collection) items.


<div class="widget-container">
    <button ng-click="widgetContainerCtrl.add()">Add Widget</button>
    <div ui-sortable="widgetContainerCtrl.sortableOptions" ng-model="widgetContainerCtrl.widgets">
      <div widget-item ng-repeat="widget in widgetContainerCtrl.widgets"
        widget="widget"
        data-id="{{widget.id}}" data-pos="{{widget.pos}}">
        <span class="handle">
          <i class="glyphicon glyphicon-move"></i>
        </span>
        <button ng-click="widgetContainerCtrl.remove(widget)">
          <i class="glyphicon glyphicon-trash"></i>
        </button>
        <span>{{widget.id}}</span>
        <span>{{widget.pos}}</span>
        <span>I'm the widget, gotta Love me!</span>
      </div>
    </div>
</div>

We’ve got to be careful with the DOM structure to satisfy ui-sortable — the ng-repeat needs to be directly below ui-sortable.

Directive JavaScript


  var app = angular.module("app", ["ui.sortable"]);
  
  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", WidgetContainerController]);
  
  function WidgetContainerController($scope, $timeout) {
    var _this = this;
    this.$scope = $scope;
    this.$timeout = $timeout;
    this.widgets = [];
    this.sortableOptions = {
      handle: "< .handle",
      update: function(event, ui) {
        _this.reorder();
      }
    };
  }

  WidgetContainerController.prototype.add = function() {
    // this.widgets.push()
  }
  WidgetContainerController.prototype.remove = function(widget) {
    // this.widgets.splice()
  }
  WidgetContainerController.prototype.reorder = function() {
    // reassign widget.pos
  }

Here’s the child directive:


  app.directive("widgetItem", [WidgetItem]);
  
  function WidgetItem() {
    return {
      restrict: "A",
      scope: {
        widget: "=";
      },
      controller: "WidgetItemController as widgetItemCtrl",
      link: function(scope, element, attrs, ctrl) { }
    };
  }
  
  app.controller("WidgetItemController", ["$scope", WidgetItemController]);
  
  function WidgetItemController($scope) {
    this.widget = $scope.widget;
  }
  WidgetItem.prototype.doSomething = function() { }

Advertisements

Datepicker With Bootstrap Icon

This is an update to a previous a post jQuery Datepicker With Bootstrap Icon but instead of the jQuery UI datepicker we will be using a Bootstrap datepicker.

The problem again is we want to be able to click on an icon to trigger the datepicker without having to write any javascript. The idea is the same as in the previous solutionUse the label’s for attribute to trigger the date’s input field.

Here is what we want the control to look like:

bootstrap-datepicker-retina

HTML:

<div class="input-group">
    <label class="input-group-btn" for="date-fld">
        <span class="btn btn-default">
            <span class="glyphicon glyphicon-calendar"></span>
        </span>
    </label>
    <input type="text" class="form-control date-input" id="date-fld" />
</div>

Some things to note:

  1. We are using the Button Addon .input-group-btn instead of the slightly simpler markup for .input-group-addon. This will give the user better UI hints when the cursor is over the icon.
  2. The <button> has been changed to a <span>. Without this change the datepicker is not triggered. You could, instead, use the button and nest a label within the button but this does not render nicely.

For completeness here is the javascript:

$(".date-input").datepicker({
    // options
});

A working example on jsFiddle.

Libraries in this article:
  1. Bootstrap 3.2.0
  2. https://github.com/eternicode/bootstrap-datepicker

jQuery Datepicker With Bootstrap Icon

Update (2014-08-16):
Not using jQuery UI datepicker? See Datepicker With Bootstrap Icon with eternicode’s Bootstrap-datepicker and Bootstrap 3.

The Problem

I recently needed to use the jQuery UI Datepicker but I also wanted to use Bootstrap’s calendar icon. Simple enough, I thought, the datepicker allows me to specify an icon image. Unfortunately, the built-in datepicker option inserts an img tag and it’s not so easy to add a CSS class needed to use a sprite instead.

Continue reading “jQuery Datepicker With Bootstrap Icon”