Au revoir Django forms

A few months ago, I released version 0.1.0 of django-rest-fomly, and I think that it’s time to speak about the project. First, I’ll speak about the reasons motivating me to start the project, then I’ll speak about the tool itself.

1. Why django-rest-formly ?

I start using Django since 2011, and I really like it, especially because it’s a real web framework and there is a great and active community behind it. From a design perspective, I like the fact that it emphasizes DRY and CoC principles. Besides, Django comes with powerful batteries making web development rapid, including forms, templates, admin site, ORM , etc. I like all these packages, but I think that some of them, like forms, aren’t useful anymore.  Nowadays, we speak about Single Page Application (SPA), web 2.0 and Internet of Thing (IoT). In such world, there is no need for Django forms package. Yep, there are a lot of packages developed for web 1.0 and the DSF community is aware of it. In fact, they’re acting according to this reality. On December 2015, Mozilla awarded $150,000 for rewriting Django to support WebSocket and to integrate key parts of Django REST Framework, among other things (more information here).

As a software engineer, I understand the importance of separating backend from frontend, and this is what I do. This is a good practice that you had to adopt if you aren’t. One of the advantages of this practice is the possibility to use the best tool for each part. Personally, I use AngularJS in the frontend, the Angular application communicates with the backend through a RESTful interface built using Django REST framework. However, I found myself writing by hand what Django forms was doing for me, and I didn’t like that, this is a waste of time. I spent a lot of time looking for a solution that I can use to solve this problem but I didn’t find any frontend package. So, I decided to create a generic solution to this use-case.

The idea was very simple. I need an Angular module which could replace Django forms package. In other words, this angular module should be able to create forms from a configuration object, add validation for fields, etc. Generally, I didn’t like the idea of building something from scratch, especially if I find something very powerful. In my case, it was the angular-formly module: It offers all that I expect and more, but the configuration structure is not compatible with the Django REST framework. angular-formly expects something like this:

{
    key: 'email',
    type: 'input',
    templateOptions: {
        type: 'email',
        label: 'Email address',
        placeholder: 'Enter email'
    }
}

below Django REST metadata for email field:

{
  "actions": {
    "POST": {
        "email": {
            "type": "email",
            "required": false,
            "read_only": false,
            "label": "Email address"
        }
    }
  }
}

Now, I think that the idea becomes clear. django-rest-formly project gives you MAINLY a CLI tool able to create an angular-formly form configuration object for any Django REST endpoint.

2. Installation

django-rest-formly is a CLI tool build on top of Node.js. So,  you can install it with npm (Node Package Manager) :

$ npm install -g django-rest-formly

3. How to use it

If you already installed the package, the django-rest-formly command should be available. django-rest-formly has two commands:

  • list: which list all available endpoints from the root API
  • form: which return the angular-formly form configuration for a given endpoint

Let’s suppose that we have a REST API at http://127.0.0.1:8000/api/v1/, I can list all existing endpoints with this command:

$ django-rest-formly list --host 127.0.0.1 --port 8000 --root /api/v1
Available endpoints:
  snippets: http://127.0.0.1:8000/snippets.json
  users: http://127.0.0.1:8000/users.json

To have an idea about the users’ endpoint, we had to use the form command:

$ django-rest-formly form --host 127.0.0.1 --port 8000 --root /api/v1 users

I think that it’ll be better that you interact with the tool. So I recommend you to follow the below steps:

1) clone the django-rest-framework-tutorial repository from my GitHub account: if you have git installed, just run

$ git clone http://github.com/benzid-wael/todo

2) Now, install create a python virtual environment and install the dependencies:

$ cd /path/to/django-rest-framework-tutorial
$ virtualenv --no-site-packages env
(env) $ pip install -r requirements.txt

3) Now, we can start the server

$ python manage.py runserver

Super! To list all available endpoints, just run the below command:

$ django-rest-formly list --host 127.0.0.1 --port 8000
Available endpoints:
  tasks: http://127.0.0.1:8000/tasks.json
  users: http://127.0.0.1:8000/users.json

Now let’s have a look into the tasks endpoint, we’ll use for that the form command:

$ django-rest-formly form --host 127.0.0.1 --port 8000 tasks

Now you can use the JSON output, to generate the correspondent form to your endpoint with form validation in place:

/* global angular */
(function() {
  'use strict';

  var app = angular.module('djangoRestFormlyExample', ['formly', 'formlyBootstrap']);

  app.controller('MainCtrl', function MainCtrl(formlyVersion) {
    var vm = this;
    // function assignment
    vm.onSubmit = onSubmit;

    // variable assignment
    vm.author = { // optionally fill in your info below 🙂
      name: 'Wael BEN ZID<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>'
    };
    vm.exampleTitle = 'Introduction';
    vm.env = {
      angularVersion: angular.version.full,
      formlyVersion: formlyVersion
    };

    vm.model = {
      note: "",
      score: 0
    };
    vm.options = {
      formState: {
        awesomeIsForced: false
      }
    };

    vm.fields = DjangoRestFormly.toFormly(formFieldConfig);

    // function definition
    function onSubmit() {
      alert("You clicked on 'Submit' button");
    }
  });

})();

Hope you enjoyed the tutorial.

Advertisements

The reason AngularJS will success: Part 2

As promised, this is the second round of this series :). I will discuss today, the four George’s tests listed bellow:

  • Load elements onto a page
  • User clicks on stuff
  • Use AJAX calls to…
  • Manipulate DOM elements

I will discuss his examples one by one following the order in his post:

Ajax calls

The author include the below 2 examples:

jQuery

$.ajax({
  url: '/ajax.php',
  dataType: 'JSON',
  success: function (data) {
    $('#element').html(data);
  },
  fail: function (data) {
    alert("AJAX failed!");
  }
});

AngularJS

$scope.myData = {};
$scope.myData.doClick = function (item, event) {
  var responsePromise = $http.get("/ajax.php");
  responsePromise.success(function(data, status, headers, config) {
    $scope.myData.fromServer = data.title;
  });
  responsePromise.error(function(data, status, headers, config) {
    alert("AJAX failed!");
  });
}

The author consider that jQuery have less code. But, he didn’t mention that the Angular code do more than a simple ajax call. In fact, it has this features:

  • Ajax call
  • Click event trigger
  • Two-way data binding
  • Looser-coupling with the DOM, because we don’t manipulate the DOM directly

Try to implement all this features with jQuery and you will see how AngularJS care for your time and the quality of your code. Furthermore, $http service supports JSONP and managing HTTP headers explicitly and in a fashion way.

DOM Manipulation

For this section, the author used the below example:

var myApp = angular.module('myApp', []);

myApp.directive('myWidget', function() {
  var linkFn;
  linkFn = function(scope, element, attrs) {
    var animateDown, animateRight, pageOne, pageTwo;
    pageOne = angular.element(element.children()[0]);
    pageTwo = angular.element(element.children()[1]);

    animateDown = function() {
      $(this).animate({
        top: '+=50'
      });
    };

    animateRight = function() {
      $(this).animate({
        left: '+=50'
      });
    };

    $(pageOne).on('click', animateDown);
    $(pageTwo).on('click', animateRight);
  };
  return {
    restrict: 'E',
    link: linkFn
  };
});

Firstable, I should notice here that he does not attack this part properly, because Angular directives are a sophisticated solution in which the purpose is extending the HTML by designing reusable component. Personally, I would appreciate that he starts by introducing Angular templating and built-in directives such as ngClick, ngHide, etc.

Secondly, the author hated the fact that we use jQuery in the above example . It’s clear now that he didn’t make any effort to understand why MVC frameworks, like AngularJS, have seen the light: Angular developers don’t want to replace jQuery but they want to provide a set of utilities to facilitate the creation of maintainable front-end applications. Indeed, they use jQuery or jqLite to manipulate the DOM.

jqLite is a tiny, API-compatible subset of jQuery that allows Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most commonly needed functionality with the goal of having a very small footprint.

Scalability

This is the most interesting section, in which we can see the quality of applications that the author write. I don’t want to discuss this because maybe he have some reasons that I can’t imagine. But personally, I do anything to avoid write such a code. Yet, We can use this use case to highlight the power of AngularJS.

The author should separate the logic from the view. So, the back-end should send real data:

{
  products: [
    productA : {
      productId: 345,
      name: "product A",
      price: 120;
      imageURL: "/public/uploads/products/productA.png",
      description: "this is the description of product A",
      colors: ['red', 'blue'],
      sizes: [34, 36, 40]
    }
  ]
}

We will define a Product service to wrap product list endpoint. For this use case, Angular provide an ngRessource module that make it easy to consume REST APIs.

var productServices = angular.module('productServices', ['ngResource']);

productServices.factory('Product', ['$resource',
  function($resource){
    return $resource('products/:productId.json', {}, {
      query: {method:'GET', params:{productId:'products'}, isArray:true}
    });
  }]);

The controller should look like this:

myApp.controller('ProductList', ['$scope', 'Product', function($scope, Product) {
  $scope.products = Product.query();
}]);

and at the view level, we will have something like that:

<ul>
  <li ng-repeat="p in products">
    <img src="{{ p.imageURL }}"/>
    <span>{{ p.name }}</span>
    <b>Price: </b>{{ p.price }}
    <p>{{ p.description }}</p>
  </li>
</ul>

As you can see, the Angular solution is easier to understand, more elegant, more structured and less code (10/48 lines only !).

Finally, I notice that if you don’t want to send the whole data for any reason, you should send a patch for the modified data. Then you merge it with the existing one at the client level (on your Angular $service). Here comes the magic of AngularJS which supports two-way data binding.

The reason AngularJS will success: Part 1

Recently, I read ‘s post “the reason AngularJS will fail“, that reduce AngularJS’s value. In my opinion, he compared it with jQuery which are incomparable. Also, the result of the comparison is false.

Let’s discuss the idea of comparison: jQuery is a cross-browser JavaScript library designed mainly to simplify document traversal and manipulation. However, AngularJS is a client-side framework (a framework is a collection of software libraries providing reasonable default interface, and generally driven by patterns). In other words, the main differences are:

  • Libraries are generally more expressing
  • Libraries allow us to learn the API as needed
  • Framework requires holistic understanding
  • Framework bring structure to large amount of code

As you see comparing jQuery to AngularJS is like comparing a text editor to an IDE, this does not means that the text editor is not more useful, but simply because the IDE has a big scope of features than the text editor. Eventually, you can extends the text editor with new features such as auto-complete, syntax highlighting, etc and you will have an IDE.

Is AngularJS difficult ?

According to the author, Angular will fails because it’s difficult. First of all, I agree with him that AngularJS is more difficult than jQuery, and that’s intuitive because frameworks are always more difficult than libraries, but this difficulty bring us more modularity, maintainability and testability, and make both development and developer’s life more easy. However, I don’t agree with him that Angular is difficult. It’s clear that it’s not intuitive but it doesn’t mean that it’s difficult, you can learn AngularJS fundamentals in 60 minutes (see this video), yes absolutely in just 60 minutes.

In the other hands, frameworks doesn’t fail because they are difficult, but they fail if their difficulties are not worth the results they produce. A chain saw is more difficult than a saw: you must be sure that it’s fuelled up and oiled. But is it useful? If you don’t want to burden your head with application architecture and best practice, just use jQuery and manipulate the DOM by your hand and you will discover as soon as your application grow that your code sucks and you not find any solution than rebuild it from scratch using any JavaScript framework.

Is AngularJS sucks ?

Another point discussed in the first author’s part, is that « doing a google search on “jQuery sucks” vs “AngularJS sucks” shows that there are more results for the latter ». Wow !! this is very convincing. Let’s try to compare each one features in an objective way:

jQuery VS AngularJS
jQuery VS AngularJS

I notice, that we can extend jQuery’s features using 3-rd party libraries and jQuery plugins.

Finally, I want to reminder you that jQuery is a wonderful library, but it can not replace any JavaScript framework. So, when you’re in a situation that jQuery is all you need then you SHOULD USE IT.

I’m gonna discuss the rest of his post in my next posts.