Creating a sortable list with Ionic and Dragula

December 15, 2017, 9:00 am Categories:

Categories

Drag and drop functionality is a nice UI feature that adds an extra touch of interactivity for users engaging with your applications.

Over the following tutorial I'll show you how to create a sortable list for an Ionic project using the Dragula plugin which is designed for adding drag and drop features to an Angular based application.

Here's what we'll be creating:

The default list display for the sortable Ionic application

When interacting with the application we can drag individual list items, drop them in different locations within the list and reorder the content like so:

Demonstrating the application when list items are in the process of being dragged, dropped and re-ordered

This will be aimed predominantly for use on desktop web browsers although the application will also work on iOS too (albeit with the unfortunate UX challenge of the page scrolling - to a certain degree - with the drag and drop movement).

Now you know what we'll be developing let's make a start by generating a brand new Ionic project.

Laying the foundation

Open your system CLI software, navigate to where you would normally store your digital projects and issue the following Ionic CLI commands to:

  • Create a new application named ionic-sortable
  • Change into the root of the ionic-sortable project directory and install the Dragula plugin
ionic start ionic-sortable blank
cd ionic-sortable
npm install ng2-dragula --save

Our final configuration step involves importing the DragulaModule into the application's root module - ionic-sortable/src/app/app.module.ts - like so:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { DragulaModule } from 'ng2-dragula/ng2-dragula';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    DragulaModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

With our project codebase now configured we can start developing the drag and drop functionality for the application.

Creating the drag and drop logic

We're going to subscribe to the Dragula plugin's drag and drop events so we can 'listen' for changes and then respond to those accordingly with our own custom events (when dropping the dragged list item).

This will allow us to retrieve data about the dragged item as well as being able to retrieve the values for the re-ordered list (which, if we wanted to, we could save to a database so that when the application is relaunched the list state is maintained across sessions).

In order to do this open the ionic-sortable/src/pages/home/home.ts component class and enter the following code:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { DragulaService } from 'ng2-dragula/ng2-dragula';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {


   /**
    * @name items
    * @type {Array} 
    * @public
    * @description     Array for holding individual object data of development technologies
    */
   public items : any = [
   						  { 
   						     name: 'Angular'
   						  }, 
   						  { 
   						     name: 'Apache Cordova'
   						  }, 
   						  { 
   						     name: 'HTML5'
   						  }, 
   						  { 
   						     name: 'Ionic Native'
   						  }, 
   						  { 
   						     name: 'npm'
   						  }, 
   						  { 
   						     name: 'Sass'
   						  }, 
   						  { 
   						     name: 'TypeScript'
   						  }];
  


   constructor(public navCtrl 	: NavController,
   			   private _DRAG 	: DragulaService) 
   {

      // Subscribe to the drag event for the list component being dragged
      // by the user
      this._DRAG.drag.subscribe((val) =>
      {
         // Log the retrieved HTML element ID value
         console.log('Is dragging: ' + val[1].id);
      });



      // Subscribe to the drop event for the list component once it has
      // been dropped into location by the user
      this._DRAG.drop.subscribe((val) =>
      {
         // Log the retrieved HTML ID value and the re-ordered list value
         console.log('Is dropped: ' + val[1].id);
         this.onDrop(val[2]);
      });
   }




   /**
    * Extract the reordered list value after the dragged list item 
    * has been dropped into its desired location
    *
    * @public
    * @method onDrop 
    * @return {None}
    */
   onDrop(val : any) : void
   {

      // Reset the items array
      this.items = [];


      // Iterate through the retrieved list data
      val.childNodes.forEach((item) =>
      {
         // Do we have data?
         if(item.id !== undefined)
         {
            // Re-populate the items array with new list order
            this.items.push({name: item.id});
         }
      });

      // Here we console log the directory structure of the array
      // but we could add functionality to save the re-populated 
      // array items (and new list order) to a database for 'session'
      //persistence
      console.dir(this.items);
   }

}

The logic for the class should be fairly self-explanatory from the commenting used in the code so let's move onto the necessary templating.

Configuring the template

The required markup for the template is incredibly simple consisting of the following items:

  • An Ionic List component that uses the dragula and dragulaModel directives to initialise the markup for drag and drop functionality
  • An ngFor loop that iterates through the items array displaying each item in its own Ionic Item component

Open the ionic-sortable/src/pages/home/home.html component view and structure the code as follows:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Sortable list
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  
  <ion-list  
     [dragula]='"first-bag"' 
     [dragulaModel]='items'>
     <ion-item
  	*ngFor="let item of items" 
  	id="{{ item.name }}">
  	   {{ item.name }}
     </ion-item>
  </ion-list>

</ion-content>

As you can see this is a relatively simple markup structure but let's discuss the following Dragula related directives:

  • dragula
  • dragulaModel

The dragula directive that’s applied to the template’s ion-list tag allows the child elements to be draggable and droppable within the context of a container identified with a value of first-bag.

As the Dragula plugin relies on named containers within which to move elements this is an important configuration step for enabling drag and drop functionality within our Ionic application

The dragulaModel directive is also placed on the ion-list element to allow dragula to sync with the array generated content (that is then iterated through with an ngFor loop)

Adding the styles

With the logic and templating for the HomePage component now in place we next need to add the following Dragula plugin style rules - able to be downloaded here - to the ionic-sortable/src/app/app.scss global stylesheet:

.gu-mirror{ 
   position:fixed!important;
   margin:0!important;
   z-index:9999!important;
   opacity:.8;
   -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
   filter:alpha(opacity=80)
}

.gu-hide{
	display:none!important
}

.gu-unselectable{
   -webkit-user-select:none!important;
   -moz-user-select:none!important;
   -ms-user-select:none!important;
   user-select:none!important
}

.gu-transit{
   opacity:.2;
   -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
   filter:alpha(opacity=20)
}

With these additional style rules for the Dragula plugin pasted inside our application’s global stylesheet our development is now completed!

At the root of your project execute the following command with the Ionic CLI to run the application in our desktop browser and test the drag and drop functionality:

ionic serve

All things being well you should see the application running in a new desktop browser window and be able to drag, drop and subsequently re-order the list items:

Demonstrating the application when list items are in the process of being dragged, dropped and re-ordered

In summary

Adding drag and drop functionality to an Ionic application is relatively simple with Dragula (although such a feature plays nicer on the web than on iOS & Android due to mobile scrolling, particularly with iOS).

Share your thoughts and reactions to this tutorial by leaving your comments in the form below.

If you enjoyed what you've read here then please consider signing up to my mailing list and, if you haven't done so already, take a look at my e-book: Mastering Ionic for further information about working with Ionic application development.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top