简体   繁体   中英

Updating global variable locally in Javascript

I started to learn Backbone.js library by implementing a simple project. After seeing a few tutorials, I produced the code which is show below. I am aware that it might not look perfect since I am new to javascript development.

So the below, I am fetching the list of nationalities from the API and then getting the number of students from those specific countries. This seems clear for the time being but the problem is, I need to get the total students per nationality which is why there is a counter in the second collection fetch function. The problem I am facing is about Javascript. Basically, defining "total" globally and updating it locally is what I need to do. I have come across to many threads similar to this one but to be honest didn't understand well enough to reproduce my own solution. Once again, my question is how I can re-engineer this code so that I can update the value of the variable "total" locally and then use the updated result outside of the inner fetch function. I appreciate your answers and advice. Thanks in advance.

    $.ajaxSetup({
    crossDomain : true,
    cache : false,
    contentType : "application/json",
    dataType : "json"
});

var baseURL = "http://lucalongo.eu:80/courses/2014-2015/questionnaireDIT/app/index.php";


var mModel = Backbone.Model.extend({});

var cNationality = Backbone.Collection.extend({
    model: mModel,
    url: this.baseURL + "/nationalities"
});

var cStudent = Backbone.Collection.extend({
    model : mModel,
    initialize : function(models, options) {
        this.url = "http://lucalongo.eu:80/courses/2014-2015/questionnaireDIT/app/index.php/students/nationality/" + options.id;
    }   
});

var vView = Backbone.View.extend({

    render: function(){
    var total = 0;
    this.collection = new cNationality();
    this.collection.fetch({
        success: function(c){
            _.each(c.models, function(col) {
               var nationalDesc = col.toJSON().description;
               var nationalID = col.toJSON().id;
               var studentNationality = new cStudent([], {id : nationalID});
                studentNationality.fetch({
                  success: function(c){
                      //console.log(nationalDesc + ": " + c.length);
                       total = total + c.length;
                      console.log(total);
                  }
               }); 
            });

        }
      });
        console.log("Total:" total); // still displays 0
    }
});


var v = new vView();
v.render();
Backbone.history.start({pushState: true});

Backbone tries to promote an event driven approach.
I think that you will ultimately end up with an event aggregator;

window.APP = {};
APP.vent = _.extend({}, Backbone.Events);

APP.vent.on("update:counter", function(increment){ 
    APP.counter = APP.counter + increment; 
}); 

From the calling code, you trigger the event:

var increment = 5 //Just an example 
APP.vent.trigger("update:counter", increment); 

Try using: {async: false} // Ajax-JQuery: Perform an asynchronous HTTP (Ajax) request

this.collection.fetch({async: false}, {
    success: function(c) {
        _.each(c.models, function(col) {
            var nationalDesc = col.toJSON().description;
            var nationalID = col.toJSON().id;
            var studentNationality = new cStudent([], {
                id: nationalID
            });
            studentNationality.fetch({
                success: function(c) {
                    //console.log(nationalDesc + ": " + c.length);
                    total = total + c.length;
                    console.log(total);
                }
            });
        });

    }
});

Links that may help you: Backbone.Sync

Let me know if it works.

Checkout the console output, you should see Total:0 first then the expected value if AJAX call works as designed. this works as designed since the callback function in the fetch options will be called after the function call fetch completes.

According to your design, you don't need a global variable total since backbone collection supports .length convention. see http://backbonejs.org/#Collection-length When your fetch function completes. see http://backbonejs.org/#Collection-fetch

I think what you're looking for is a way to manipulate total anywhere within the view. What I tend to do, in cases where I want a variable to be "global" to all my view methods is make it a property of the view. What I'm saying is,

var vView = Backbone.View.extend({

  initalize: function(){
    // Initialize your object property
    this.totalCount = 0;
  },

  render: function() {
  // Inside callbacks you will lose your view context
  // so save it
   var that = this;
   // Nested collection fetch
      success:  function(c){
        that.totalCount = that.totalCount + c.length;
        console.log(that.totalCount);
      }
   // rest of code
  }
});

Since collection fetch is a wrapper for an ajax GET (unless you override Backbone.sync ) it will run asynchronously. If you want to run code in-synch with the fetch you can do three things.

  1. Use callback functions like you do in your code
  2. Use Deferred/Promises callbacks (very similiar to 1.)
  3. Do what @KimGysen 's says: Backbone has a solid API for setting up and responding to events. (Marionettejs extends this API in very cool directions).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM