Is it possible to use method chaining assigning strings in Javascript?

586 views Asked by At

I want to use method chaining syntax using JavaScript and AngularJS. I assign arrays and strings.

This code works:

$mdDateLocaleProvider
     .shortDays = ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá']
     .msgCalendar = 'Calendario'
;

This code doesn't work:

$mdDateLocaleProvider
     .shortDays = ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá']
     .msgCalendar = 'Calendario'
     .msgOpenCalendar = 'Abrir calendario'
;

I think the msgOpenCalendar = 'Abrir calendario' sentence is failing due to the string assignment.

My solution:

$mdDateLocaleProvider
     .shortDays = ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá']
     .msgCalendar = 'Calendario'
;
$mdDateLocaleProvider
     .msgOpenCalendar = 'Abrir calendario'
;

Why is there a problem assigning a string but isn't with an array?

4

There are 4 answers

1
Ron Dadon On BEST ANSWER

The name is method chaining for a reason, it is used to chain methods, not variable assignments.

In method chaining, you are simply returning the object instance (of a mutable or a new immutable object) in the end of the method (function), so you can call the next function "right away".

The reason it "works" is that an array in JS is an object, so you simply placed a msgCalendar property on the array that you assigned to shortDays property.

Basically, what you achieved is:

var shortDays = ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá'].msgCalendar = 'Calendario';
// here shortDays actually equals to 'Calendario', because it is like writing a = b = 2.
$mdDateLocaleProvider.shortDays = shortDays;
$mdDateLocaleProvider.msgOpenCalendar = 'Abrir calendario';
0
Duncan On

You cannot use chaining, but as you included the angularjs tag in the question, you probably want to look at using angular.extend:

angular.extend($mdDateLocaleProvider, {
     shortDays: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá'],
     msgCalendar: 'Calendario',
     msgOpenCalendar: 'Abrir calendario'
});

which will have the desired effect of updating the three properties and you can even use method chaining on the result if you want to call any methods.

0
Sebas On

You cannot use method chaining with direct assignments like you're doing. As explained by Ron, what you think it does is not what it's actually doing.

A way of working around this is implementing the Builder pattern that would allow you to create objects based on chaining their setters methods.

0
Hashbrown On

You want assign().

 Object.assign($mdDateLocaleProvider, {
      shortDays : ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá']
      msgCalendar : 'Calendario'
      msgOpenCalendar : 'Abrir calendario'
 });

Which will set everything at once for you.


If you need to actually chain say like maybe set shortDays, call a function, then set msgCalendar, try my shim.
This will also work for when assign doesnt work (setting DOM onclicks or innerTexts), or you need to call a function that doesn't chain.

 wrap($mdDateLocaleProvider)
      .set('shortDays'      , ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá'])
      .set('msgCalendar'    , 'Calendario')
      .set('msgOpenCalendar', 'Abrir calendario')
 ;

Simply call wrap() and away you go.

wrap = (obj) => (Object.defineProperty(obj,
            'define', {value:(name, options) => (Object.defineProperty(obj, name, options))})
    .define('assign', {value:(props)         => (Object.assign(obj, props))                })
    .define('set'   , {value:(name, value)   => { obj[name] = value; return obj; }         })
    .define('invoke', {value:(name, ...args) => { obj[name](...args); return obj; }        })
);

Demo

let bob = {
    hello  : 'there',
    chains : () => {bob.I_RAN = true; return bob;},
    doesnt : (arg1, arg2) => {bob.I_RAN_ALSO = [arg1, arg2]; return null;}
};
wrap(bob)
    .set('oh', 'my')
    .chains()
    .invoke('doesnt', 'works', 'anyway')
    .assign({more:7, stuff:null})
;
for (let item of Object.keys(bob))
      console.log(`'${item}' : ${bob[item]}`);

Output:
enter image description here