Some Suggestions for JavaScript client application programming

  • 2020-06-19 09:45:01
  • OfStack

You may have noticed that more and more Web applications have become more complex in recent years, with the focus slowly shifting from the server to the client. Is this a normal trend? I don't know. The debate between pro and con is like a debate about the resurrection and Christmas; It is hard to say which view is absolutely right. Therefore, this article will not go into exactly which side is right, but I will try to explain that using the well-known object-oriented programming may successfully solve 1 of the problems in client programming.

An example of less formal code

Taking into account the responsiveness of an application and the user experience has led to the creation of increasingly complex code that becomes difficult to understand and maintain. You can easily imagine JavaScript application code that builds clients without any architecture and rules:


$(function(){
  $('#form').submit(function(e) {
    e.preventDefault();
 
    $.ajax({
      url: '/animals',
      type: 'POST',
      dataType: 'json',
      data: { text: $('#new-animal').find('textarea').val() },
      success: function(data) {
        $('#animals').append('<li>' + data.text + '</li>');
        $('#new-animal').find('textarea').val('');
      }
     });
   });
});

Maintaining code of this type will be difficult. Because this short piece of code has a lot to do with it: it controls a lot of events (site, user, network events), it handles the user's action events, it parses the replies returned by the server and generates the HTML code. Someone might say, "Yes, you're right, but if this isn't a single client page application ? This is at best an example of overuse of the jQuery class library "-- not a very persuasive argument, since it is well known that easy to maintain and well-designed code is important. In particular, many tools or frameworks aim to keep code available so that we can more easily test, maintain, reuse, and extend it.

What is MVC?

Let's leave it at that. We can benefit from JavaScript frameworks based on MVC, but most of them don't use MVC and are equivalent to a combination of Model and Videw, or something in between, which is hard to tell apart. This is why most of the Javascript framework is based on MV*.

Changing the approach may provide the organization and architecture of the client side of the project, making the code easier to maintain over a long period of time and relatively easy to refactor even existing code. It is important to remember how he works and the answers to the following questions.

What types of data do I have in my application? - Model What should the user see? - View Who is the program that interacts with the user? - Controller

Refactor the code using the MVC framework

What are the benefits of using MVC refactoring code?

Remove DOM and Ajax dependencies The code is better structured and easier to test. Remove the excess code from $(document).ready (), leaving only the portion that creates Links using Model.

Let's use 1 simple step to refactor a typical block of code
Step 1: Create the view and move the Ajax request

Using the prototypes builder, the schema creates the 'Animals' object and adds one 'add' method. At the same time, the view is created 'NewAnimalView' and adds methods 'addAnimal', 'appendAnimal', 'clearInput'.

The code is as follows:


var Animals = function() {
};
 
Animals.prototype.add = function (options) {
   $.ajax({
     url: '/animals',
     type: 'POST',
     dataType: 'json',
     data: { text: options.text },
     success: options.success
   });
};
 
 var NewAnimalView = function (options) {
  this.animals = options.animals;
  var add = $.proxy(this.addAnimal, this);
  $('# form').submit(add);
 };
 
 NewAnimalView.prototype.addAnimal = function(e) {
   e.preventDefault();
   var self = this;
 
   this.animals.add({
     text: $('#new-animal textarea').val(),
     success: function(data) {
       self.appendAnimal (data.text);
       self.clearInput();     
     }
   });
 };
 
NewAnimalView.prototype.appendAnimal = function(text) {
  $('#animals ul').append('<li>' + data.text + '</li>');
};
NewAnimalView.prototype.clearInput = function() {
  $('#new-animal textarea').val('');
};
 
 $(document).ready(function() {
   var animals = new Animals();
   new NewAnimalView({ animals: animals });
 });

Step 2: Use events to unrely.

For this example, leveraging the MVC framework is key. We will be using an event mechanism that allows us to combine and trigger custom events, so we create new "AnimalsView" and "NewAnimalView" and assign them different responsibilities for displaying animals. Using events to differentiate responsibilities is very simple. If responsibility is passed between methods and events, it looks like this:


var events = _.clone(Backbone.Events);
var Animals = function() {
};
 
Animals.prototype.add = function(text) {
   $.ajax({
     url: '/animals',
     type: 'POST',
     dataType: 'json',
     data: { text: text },
     success: function(data) {
      events.trigger('animal:add', data.text);
     }
   });
};
 
var NewAnimalView = function(options) {
  this.animals = options.animals;
  events.on('animal:add', this.clearAnimal, this);
  var add = $.proxy(this.addAnimal, this);
  $('# form').submit(add);
 };
 
NewAnimalView.prototype.addAnimal = function(e) {
   e.preventDefault();
   this.animals.add($('#new-animal textarea').val());
 };
 
NewAnimalView.prototype.clearInput = function() {
  $('#new-animal textarea').val('');
};
 
var AnimalsView = function() {
  events.on('animal:add', this.appendAnimal, this);
};
 
AnimalsView.prototype.appendAnimal = function(text) {
  $('#animals ul').append('<li>' + data.text + '</li>');
};
 
$(document).ready(function() {
   var animals = new Animals();
   new NewAnimalView({ animals: animals });
   new AnimalsView();
});

Step 3: Pass the data structure to the core framework

Finally, the most important step, we use: models, views and collections.


var Animal = Backbone.Model.extend({
  url: '/animals'
});
 
var Animals = Backbone.Collection.extend({
  model: Animal
});
 
var AnimalsView = Backbone.View.extend({
  initialize: function() {
    this.collection.on('add', this.appendAnimal, this);
  },
 
  appendAnimal: function(animal) {
    this.$('ul').append('<li>' + animal.escape('text') + '</li>');
  }
});
 
 
var NewAnimalView = Backbone.View.extend({
  events: {
    'submit form': 'addAnimal'
  },
 
  initialize: function() {
    this.collection.on('add', this.clearInput, this);
  },
 
  addAnimal: function(e) {
    e.preventDefault();
    this.collection.create({ text: this.$('textarea').val() });
  },
 
  clearInput: function() {
    this.$('textarea').val('');
  }
});
 
$(document).ready(function() {
  var animals = new Animals();
  new NewAnimalView({ el: $('#new-animal'), collection: animals });
  new AnimalsView({ el: $('#animals'), collection: animals });
});

conclusion

What have we achieved? We work at a high level of abstraction. Code becomes easier to maintain, refactor, and extend. We've optimized the code tremendously. Isn't that fascinating? That's great. However, I might throw cold water on the idea that even the best frameworks develop code that is still fragile and difficult to maintain. Therefore, it is a mistake to assume that using a good MV* framework will solve all code problems. Remember that during refactoring, the code gets much better after Step 2, and we don't use the framework's main components.

Keep in mind that the MV* framework is good for 1 point, but all the focus on 'How' to develop an application lets the developer head decide' What'. A complement to each framework, especially if the project's Domain is complex, will be the Domain driven design approach, which will focus more on the following aspects: "what", the process of turning requirements into real products. But that's another topic we're going to talk about.


Related articles: