Implementing Cascade Methods (Cascade) in Javascript

Asked

Viewed 508 times

4

In the book Javascript: The Good Parts, Douglas Crockford explains the concept of cascading method, from Cascade. According to the author these methods are characterized by changing the state of the object without returning anything. Nested methods return this. Follow the example taken from Crockford’s book:

getElement('myBoxDiv').
move(350, 150).
width(100).
height(100).
color('red').
border('10px outset').
padding('4px').
appendText("Please stand by").
on('mousedown', function (m) {
this.startDrag(m, this.getNinth(m));
}).
on('mousemove', 'drag').
on('mouseup', 'stopDrag').
later(2000, function ( ) {
this.
color('yellow').
setHTML("What hath God wraught?").
slide(400, 40, 200, 200);
}).
tip('This box is resizeable');

How to implement this standard with Javascript? Is there any good practice for this implementation?

2 answers

9

The function must return this. Here is an example:

function criarPessoa(nome) {
    return {
        nome: nome,
        idade: 25,
        alterarNome: function(nome) {
            this.nome = nome;
            return this;
        },
        alterarIdade: function(idade) {
            this.idade = idade;
            return this;
        }
    };
}

var pessoa = criarPessoa("Maria").alterarIdade(30).alterarNome("Paulo");
alert("Nome: " + pessoa.nome + "; Idade: " + pessoa.idade);

6


Javascript libraries often use this concept, Mootools is the most comprehensive case I believe.

To implement this idea in your code all the methods you want to chain must return a new Type/Type that contains the methods you call the following.

An example with native Javascript,

without having to do anything new:

var string = 'olá mundo!';
var letras = string.split('').filter(function(letra){ return /[a-z]/i.test(letra); }).join('');

In this case what happens?

We have a string as the starting point. Applying the method .split('') we no longer have a string and we have an array. Now we have changed String Type for Object/Array Type. The product of this first method was:

["o", "l", "á", " ", "m", "u", "n", "d", "o", "!"]

This array will be the material/input that the next method will use. The next method .filter() will remove from this array values that are not "plain" letters. The pruduto will be an array yet a Array type which will be passed to the arrays method .join() that will return a String.

In this example we use native cascade code. (Demo online: http://jsfiddle.net/8ubcL83q/)

To apply the same concept the code made by you must take into account that all methods you call have to produce/return something that can be used in the next chained method for the cascade to work.

The way to do this is to ensure that at the end of the method there is a return. After that return comes what wants to return:

return variavelComProdutoParaOProximoMetodoConsumir;

Analyzing your code I see that it starts with a getter getElement('myBoxDiv') which returns a DOM object/element. From there, analyzing what is being done, I deduce that all these methods have at their end return this; and thus all these methods are being applied to the same element with which the chain/cascade started.

An example of code using the Mootools library:

(online demo here)

document.id('foo').getParent('div').setStyle('border', '2px solid #ccf').addEvent('click', function(){
   alert(this.get('text')); 
});

In this case document.id('foo') is a function that Mootools added to the object document, which passes as argument a string, "foo". This function/method fetches the DOM element with the ID foo and returns a object/ element of the GIFT.

Then the .getParent('div') will rise in the DOM and return the first div what to find. This new object/ DOM element will be the product used in the next method. So .setStyle('border', '2px solid #ccf') will apply a line to the edge of the element.

This method to apply CSS returns the element you modified. Like your example, the setStyle() does what is requested and returns the DOM element.

Thus it is possible for the next method to be applied to this element.

Note that Mootools adds new methods to the Elements prototype, so it is very useful to return the object this at the end of each method.

To make your own code cascading:

Here’s an example, with the same functionality as my Mootools example does:

var metodos = {
    objeto: null,
    getID: function (seletor) {
        var el = document.getElementById(seletor);
        this.objeto = el;
        return this;
    },
    getParent: function (tag) {
        tag = tag.toUpperCase();
        var elm = this.objeto, x = 0;
        while (elm.nodeName != tag && elm.nodeName != 'body') {
            elm = elm.parentNode;
        }
        this.objeto = elm;
        return this;
    },
    setStyle: function (propriedade, valor) {
        this.objeto.style[propriedade] = valor;
        return this;
    },
    addEvent: function (tipo) {
        this.objeto.addEventListener(tipo, function () {
            alert('Estou a funcionar!');
        });
        return this;
    }
}
metodos.getID('foo').getParent('div').setStyle('border', '2px solid #ccf').addEvent('click');
div {
    padding: 10px;
}
<div>
    <div><span>Span 1</span>

    </div>
    <div><span id="foo">Span 2 (pode clicar aqui...)</span>

    </div>
</div>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.