What is the difference between Function() {} and () => {}? Why doesn’t $http.get work?

Asked

Viewed 4,688 times

13

When I use

 $http.get('/products').then((response) => {
   this.products = response.data;
   this.allProducts = response.data;
 });

the page is loaded with the products in Google Chrome, but when I use

$http.get('/products').then(function(response) {
  this.products = response.data;
  this.allProducts = response.data;
});

Products are not loaded :(

Because of Safari and Safari Mobile, I am unable to use the syntax () => of ES2015. The browser gives a "build error".

Does anyone know what I need to do to use the function(response) {} and get the products?

Thank you

  • Any error appears in the console, the request is made?

  • the request is made yes. When I give a console.log(response.data) it returns me the right product array. But an error appears : TypeError: Cannot set property 'products' of undefined

  • Tries to initialize the product list, products = []; in the overall scope

3 answers

20


As I noticed they didn’t explain the difference between () => {} and function() {}, then although there is an answer marked as correct, I will explain this difference.

First of all it is very common to think that both codes are equivalent, since the ES6 brought several syntax sugar to make the code more readable and concise, the arrow functions are usually confused with functions of ES5. But getting to the point there are five differences between both codes:

Context

Arrow functions possess this léxico while the normal model has this dinâmico. It means that arrow functions inherit the local context from which it was declared, while the normal model has the context associated with the object it is linked to at the time of the call (if it is not associated with anyone in the call, it will assume this automatically as the global context, which in the case of browsers is window)

var normal = function() {
  return this === obj;
};

var arrow = () => {
  return this === window;
};

var obj = { normal: normal, arrow: arrow };

obj.normal(); // true
obj.arrow(); // true

normal(); // false

Constructor

Arrow functions cannot be constructors, then it is not possible to use the operator new with the same.

var Normal = function() {};
var Arrow = () => {};

new Normal(); // Normal {}
new Arrow(); // Arrow is not a constructor

Arguments

Arrow functions does not have the array-like object arguments.

var noop = () => {
  return arguments;
}

noop(); // ReferenceError: arguments is not defined

Function name

Function expressions can be named explicatively, this is useful in some scenarios involving recursion and for in cases of exception it is easier to track code, since the function name is used in the exception stack shown to the developer. Only that Arrows Functions cannot be named explicitly, they end up inheriting the name of the variable where it was created.

var fn = function nome() {};
fn.name; // nome

var fn = () => {};
fn.name; // fn

Return

Function expressions need to explicitly state what the function return will be, while Arrow Functions allow writing in a shortened template where the last analyzed expression will be the return of the function when keys are omitted {}.

var fn = function() { return 1; }; // retorna 1

var fn = () => 1; // retorna 1
var fn = () => (1, 2, 3); // retorna 3, última expressão avaliada

var fn = () => { 1 }; // retorna undefined
var fn = () => { return 1 }; // retorna 1

What would be an equivalent model of () => {} then?

Ignoring the case that arrow functions cannot be used as constructors and do not receive arguments, the most equivalent model between arrow functions and traditional functions would be this:

// modelo nomeado
var name = (() => { /* code */ })
var name = (function name() { /* code */ }).bind(this)

// modelo anônimo
(() => { /* code */ })
(function() { /* code */ }).bind(this)

In this case the code can be exactly the same between the two models and they will work exactly the same. But of course, there are other ways to simulate the behavior of arrow functions. One of them is to store the context this in a variable and use that variable in the traditional function instead of its own this, what the other answers showed.

  • 1

    Well put! I focused on the text of the question and forgot the title.

  • 1

    Good answer! I find it interesting to mention the Return sugar syntax with Arrow Function. Example Function (test) { Return test } can be written only with test => test. How would you like to add an example to the answer?

  • Good point raised, @Dorivalzanetto. I also need to update the Nome de função, since Arrow functions now take by default the name of the variable where it was declared in the name property.

  • Bacana @Gabrielkatakura. I asked a question about the loss of references in functions that I could only solve with Arrow functions. What do you think about trying to come up with an answer? http://answall.com/questions/178215/perda-de-refer%C3%Aancia-em-chamada-de-fun%C3%A7%C3%A3o

  • @Dorivalzanetto just saw your question, but she just got an answer (which I looked at and she’s correct). I can think of four other plausible solutions to solve your problem there, over night I put an answer

7

I may be mistaken, but I read an article by Angularjs (I’m not finding the reference now) that dealt with this specific issue when combined with the use of the method syntax as, where it is common to use this within the controller.

The big problem with that is knowing what scope the this is assigned, because in order to be able to pass the data to the view, it is necessary that it is in the scope of the controller.

That’s where I believe your mistake is, because this is in the scope of $http

.controller('myCtrl', function($scope, $http) {
    this.products = []; //Aqui ele está no escopo do controller - Irá passar para view

    $http.get('minha/url/aqui').then(function(response){
        this.products = response.data; //Aqui ele está no escopo do $http - Não irá passar para view
    })
})

What is normally done, to ensure that you always use the scope of controller when assigned to the this, is to create a variable at the beginning of controller and use it instead of using this. Thus:

.controller('myCtrl', function($scope, $http) {
    var vm = this; //Pode ser vm (ViewModel) ou outra variável de sua preferência

    vm.products = []; //Aqui ele está no escopo do controller - Irá passar para view

    $http.get('minha/url/aqui').then(function(response){
        vm.products = response.data; //Está apenas atualizando o products definido anteriormente
    })
})
  • Great answer. An alternative to not using the list in the view is not using the this.

0

I do it like this and it works:

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

angular.module('myApp')
.controller('myCtrl', function($scope, $http) {

    $scope.content = [];

    $http.get("/content")
    .then(function(response) {
        $scope.content = response.data;
    });

});

Taken and based on: Angular HTTP W3schools

  • I needed the products variable to be from the controller and not $Scope.

  • I only know how to do as the documentation of W3schools and Angular itself do. :-(

Browser other questions tagged

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