In the first JavaScript tutorial, we learned about objects. I mean, real objects:
the kind you can instantiate by creating a constructor function, and then adding
all the methods via the prototype. Objects look a lot different in PHP than in
in JavaScript, in large part because PHP has classes and JavaScript doesn't. Well...
that's a big fat lie! ES2015 introduces classes: true classes.

Creating a new class

As a PHP developer, you're going to love this... because the class structure looks
nearly identical to PHP! If you want to create a Helper class... just say,
class Helper {}:

203 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

... lines 4 - 172

/**

* A "private" object

*/

classHelper{

}

... lines 179 - 201

})(window, jQuery, Routing, swal);

That's it! With this syntax, the constructor is called, just, constructor. Move
the old constructor function into the class and rename it: constructor. You can
also remove the semicolon after the method, just like in PHP:

201 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

... lines 4 - 172

/**

* A "private" object

*/

classHelper{

constructor($wrapper) {

this.$wrapper = $wrapper;

}

... lines 180 - 198

}

})(window, jQuery, Routing, swal);

Moving everything else into the new class syntax is easy: remove $.extend(helper.prototype)
and move all of the methods inside of the class:

201 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

... lines 4 - 172

/**

* A "private" object

*/

classHelper{

constructor($wrapper) {

this.$wrapper = $wrapper;

}

calculateTotalWeight() {

let totalWeight = 0;

this.$wrapper.find('tbody tr').each((index, element) => {

totalWeight += $(element).data('weight');

});

return totalWeight;

}

getTotalWeightString(maxWeight = 500) {

let weight = this.calculateTotalWeight();

if (weight > maxWeight) {

weight = maxWeight + '+';

}

return weight + ' lbs';

}

}

})(window, jQuery, Routing, swal);

And congratulations! We just created a new ES2015 class. Wasn't that nice?

To make things sweeter, it all works just like before: nothing is broken. And that's
no accident: behind the scenes, JavaScript still follows the prototypical object
oriented model. This new syntax is just a nice wrapper around it. It's great: we
don't need to worry about the prototype, but ultimately, that is set behind the
scenes.

Let's make the same change at the top with RepLogApp: class RepLogApp { and
then move the old constructor function inside. But, make sure to spell that correctly!
I'll indent everything and add the closing curly brace:

203 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

classRepLogApp{

constructor($wrapper) {

this.$wrapper = $wrapper;

this.helper = new Helper(this.$wrapper);

this.loadRepLogs();

this.$wrapper.on(

'click',

'.js-delete-rep-log',

this.handleRepLogDelete.bind(this)

);

this.$wrapper.on(

'click',

'tbody tr',

this.handleRowClick.bind(this)

);

this.$wrapper.on(

'submit',

this._selectors.newRepForm,

this.handleNewFormSubmit.bind(this)

);

}

}

... lines 28 - 201

})(window, jQuery, Routing, swal);

Cool! Now we all we need to do is move the methods inside!

Classes do not have Properties

Start by only moving the _selectors property. Paste it inside the class and...
woh! PhpStorm is super angry:

Types are not supported by current JavaScript version

Rude! PhpStorm is trying to tell us that properties are not supported inside
classes: only methods are allowed. That may seem weird - but it'll be more clear
why in a minute. For now, change this to be a method: _getSelectors(). Add a
return statement, and everything is happy:

207 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

classRepLogApp{

... lines 5 - 27

_getSelectors() {

return {

newRepForm: '.js-new-rep-log-form'

}

}

}

... lines 34 - 205

})(window, jQuery, Routing, swal);

Well, everything except for the couple of places where we reference the _selectors
property. Yea, this._selectors, that's not going to work:

207 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

classRepLogApp{

constructor($wrapper) {

... lines 6 - 20

this.$wrapper.on(

... line 22

this._selectors.newRepForm,

... line 24

);

}

... lines 27 - 135

_mapErrorsToForm(errorData) {

... line 137

const $form = this.$wrapper.find(this._selectors.newRepForm);

... lines 139 - 152

},

_removeFormErrors() {

const $form = this.$wrapper.find(this._selectors.newRepForm);

... lines 157 - 158

},

_clearForm() {

... lines 162 - 163

const $form = this.$wrapper.find(this._selectors.newRepForm);

... line 165

},

... lines 167 - 176

});

... lines 178 - 205

})(window, jQuery, Routing, swal);

But don't fix it! Let's come back in a minute.

Right now, move the rest of the methods inside: just delete the } and the prototype
line to do it. We can also remove the comma after each method:

203 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

classRepLogApp{

constructor($wrapper) {

... lines 6 - 25

}

_getSelectors() {

return {

newRepForm: '.js-new-rep-log-form'

}

}

loadRepLogs() {

... lines 35 - 41

}

updateTotalWeightLifted() {

... lines 45 - 47

}

handleRepLogDelete(e) {

... lines 51 - 63

}

_deleteRepLog($link) {

... lines 67 - 84

}

handleRowClick() {

... line 88

}

handleNewFormSubmit(e) {

... lines 92 - 106

}

_saveRepLog(data) {

... lines 110 - 129

}

_mapErrorsToForm(errorData) {

... lines 133 - 148

}

_removeFormErrors() {

... lines 152 - 154

}

_clearForm() {

... lines 158 - 161

}

_addRow(repLog) {

... lines 165 - 171

}

}

... lines 174 - 201

})(window, jQuery, Routing, swal);

Other than that, nothing needs to change.

Magic get Methods

Time to go back and fix this _getSelectors() problem. The easiest thing would be
to update this._selectors to this._getSelectors(). But, there's a cooler
way.

Rename the method back to _selectors(), and then add a "get space" in front of
it:

206 lines web/assets/js/RepLogApp.js

'use strict';

(function(window, $, Routing, swal) {

classRepLogApp{

... lines 5 - 27

/**

* Call like this.selectors

*/

get _selectors() {

... lines 32 - 34

}

... lines 36 - 175

}

... lines 177 - 204

})(window, jQuery, Routing, swal);

Woh! Instantly, PhpStorm is happy: this is a valid syntax. And when you search
for _selectors, PhpStorm is happy about those calls too!

This is the new "get" syntax: a special new feature from ES2015 that allows you
to define a method that should be called whenever someone tries to access a property,
like _selectors. There's of course also a "set" version of this, which would be
called when someone tries to set the _selectors property.

So even though classes don't technically support properties, you can effectively
create properties by using these get and set methods.

Oh, and btw, just to be clear: even though you can't define a property on a class,
you can still set whatever properties you want on the object, after it's instantiated:

Leave a comment!

In this case, I think it's ok because that function seems like you may want to use it from outside of the class. It just updates the total, but anyways, you can always add that "underscore" if you find any method not being used from outside (as soon as you need that, then you can refactor that method's name)

2018-05-23Nacer

Hi @Diego sorry for the confusion between static and private, but i don"t understand yet the diffecrence bettwen _addRow and updateTotalWeightLifted, why updateTotalWeightLifted dosn't start with underscore like addRow for example ?

That method cannot be static because it uses some properties of the class, and the "under score" convention for naming methods is for specifying which methods should be considered as "private", just like if you were declaring a "private function" in PHP

Cheers!

2018-05-22Nacer

Hello, can someone explain me why the function updateTotalWeightLifted is not a static and don't begin with underscore like _addRow for example, Thx :)