RSB
RSB

Reputation: 111

Backbone.js: Populating collections separately

I am working on a project in Backbone.js were I get the results from a Food API and then display them. I can click an item from the results list and be able to save that result, showing it in the foods tracked list on the right side of the page.

The foods tracked list shows the information about the Food (Food Name, Brand and Calories) as well as a total amount of calories from all the foods tracked.

The app should also be able to work when you click on the add to meal button.

The new implementation of my code designed for persistent storing and collection of total calories for each meal creates a separate collection for each meal.

I thought would that allow each collection to be populated separately for each meal and each collection can add up it's calories. However, when I click on an item in the search results list the item is appended to all the meals and the tracked foods list, instead of just the tracked foods list.

I have tried the solution offered but I don't know how to create multiple firebase urls and have searched the internet for this information.

Also there is an error with the add to meal functionality because I am trying to remove and add a class in the addClicked function.

Here is a jsfiddle

$(function() {

    var Food = Backbone.Model.extend({

        defaults: {
            title: 'no information found',
            brand: 'no information found',
            calories: 'no information found',
            day: 'all'
        }
    });

    var AllFoods = Backbone.Firebase.Collection.extend({
        model: Food,
        url: "https://blinding-torch-8751.firebaseio.com/"

    });
    var Breakfast = Backbone.Firebase.Collection.extend({
        model: Food,
        url: "https://blinding-torch-8751.firebaseio.com/"

    });
    var Lunch = Backbone.Firebase.Collection.extend({
        model: Food,
        url: "https://blinding-torch-8751.firebaseio.com/"

    });
    var Dinner = Backbone.Firebase.Collection.extend({
        model: Food,
        url: "https://blinding-torch-8751.firebaseio.com/"

    });
    var Snack = Backbone.Firebase.Collection.extend({
        model: Food,
        url: "https://blinding-torch-8751.firebaseio.com/"

    });



    var SearchList = Backbone.Collection.extend({

        initialize: function() {
            this.bind("reset", function(model, options) {
                console.log("Inside event");
                console.log(model);
            });
        },

        //** 1. Function "parse" is a Backbone function to parse the response properly
        parse: function(response) {
            //** return the array hits inside response, when returning the array
            //** we let Backone populate this collection
            return response.hits;
        }

    });


    var App = Backbone.View.extend({

        el: 'body',

        events: {
            "input #searchBox": "prepCollection",
            "click #listing li": "track",
            "click #add": "addClicked",
            "click #remove": "removeClicked"

        },

        initialize: function() {

            this.model = new SearchList();
            this.foods = new AllFoods();
            this.breakfastlist = new Breakfast();
            this.lunchlist = new Lunch();
            this.dinnerlist = new Dinner();
            this.snacklist = new Snack();
            this.prepCollection = _.debounce(this.prepCollection, 1000);
            this.$total = $('#total span');
            this.$list = $('#listing');
            this.$instruct = $('#instruct');
            this.$tracked = $('#tracked');
            this.listenTo(this.foods, 'add', this.rendertracked);
            this.listenTo(this.foods, 'remove', this.rendertracked);
            this.listenTo(this.breakfastlist, 'add', this.renderbreakfast);
            this.listenTo(this.breakfastlist, 'remove', this.renderbreakfast);
            this.listenTo(this.lunchlist, 'add', this.renderlunch);
            this.listenTo(this.lunchlist, 'remove', this.renderlunch);
            this.listenTo(this.dinnerlist, 'add', this.renderdinner);
            this.listenTo(this.dinnerlist, 'remove', this.renderdinner);
            this.listenTo(this.snacklist, 'add', this.rendersnack);
            this.listenTo(this.snacklist, 'remove', this.rendersnack);

        },

        addClicked: function(e) {
            var $target = $(e.currentTarget).parent();
            var $selected = $target.find('#mySelect').val();
            var mealClass= $target.attr('class');
            var location = $target.attr('data-id');
            var currentFood = this.foods.get(location);
            var currenthtml = currentFood.get('html');

            //replaces class in order to use it later to specifically target items in a specific meal collection
            currenthtml.removeClass('alltracked').addClass($selected);

            switch ($selected) {
                case 'Breakfast':
                    this.breakfastlist.create(currentFood);
                    break;
                case 'Lunch':
                    this.lunchlist.create(currentFood);
                    break;
                case 'Dinner':
                    this.dinnerlist.create(currentFood)
                    break;
                case 'Snack':
                    this.snacklist.create(currentFood)
                    break;
                default:
                    alert("Error: try again");

            }



        },

        removeClicked: function(e) {
            var $target = $(e.currentTarget).parent();
            var removeid = $target.attr('data-id');
            $target.remove();
            var modelRemoved = this.foods.get(removeid);
            var addedClass = $target.attr('class');
            this.foods.remove(modelRemoved);

            //uses the added class to remove from the correct collection
            switch (addedClass) {
                case 'Breakfast':
                   this.breakfastlist.remove(modelRemoved);
                   break;
                case 'Lunch':
                    this.lunchlist.remove(modelRemoved);
                    break;
                case 'Dinner':
                    this.dinnerlist.remove(modelRemoved);
                    break;
                case 'Snack':
                    this.snacklist.remove(modelRemoved);
                    break;

            }
        },

        prepCollection: function() {
            var name = $('input').val();
            var newUrl = "https://api.nutritionix.com/v1_1/search/" + name + "?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name,brand_name,item_id,nf_calories&appId=26952a04&appKey=33b9262901d0068d4895736b5af19805";

            if (name == "") {
                this.$list.html("")
                this.$instruct.html("")
            } else {
                this.$instruct.html("Click On A Food Item To Track It");
                this.model.url = newUrl;
                this.model.fetch({
                    success: function(response, xhr) {
                        console.log("Inside success");
                        console.log(response.toJSON());
                    },
                    error: function(errorResponse) {
                        console.log(errorResponse)
                    }
                });
                this.listenTo(this.model, 'sync', this.render);
            }

        },

        track: function(e) {

            var $target = $(e.currentTarget);
            var item_name = $target.attr('data-name');
            var brand_name = $target.attr('data-brand');
            var calorieString = $target.attr('data-calories');
            var calorieAmt = parseFloat(calorieString);
            var foodid = $target.attr('data-id');

            var chooseday = '<form>What meal was this part of?: <select id="mySelect"> <option value="Breakfast">Breakfast</option><option value="Lunch">Lunch</option><option value="Dinner">Dinner</option><option value="Snack">Snack</option></select></form><button id="add" type="button">Add To Meal</button><button id="remove" type="button">Remove From Tracked</button>';

            var trackedhtml = '<li' + ' data-id=' + '"' + foodid + '"' + ' class="alltracked">' + "<strong>" + item_name + '</strong>' + ' (' + brand_name + ')' + ' - ' + calorieAmt + ' Calories' + chooseday + '</li>'


            this.foods.create(new Food({
                id: foodid,
                title: item_name,
                brand: brand_name,
                calories: calorieAmt,
                html: trackedhtml
            }));

        },

        rendertracked: function() {
            var total = 0;
            var trackedhtml = '';

            this.foods.each(function(food) {
                trackedhtml = trackedhtml + food.get('html');
                total += food.get('calories');
            }, this)
            this.$tracked.html(trackedhtml);
            this.$total.html(total);

        },
        renderbreakfast: function(){
            var total = 0;
            var breakfasthtml = '';

            this.breakfastlist.each(function(dish) {
                breakfasthtml = breakfasthtml + dish.get('html');
                total += dish.get('calories');
            }, this)
            $('#breakfast').html(breakfasthtml);
            $('#totalbreak').html(total);


        },
        renderlunch: function(){
            var total = 0;
            var lunchtml = '';

            this.lunchlist.each(function(dish) {
                lunchtml = lunchtml + dish.get('html');
                total += dish.get('calories');
            }, this)
            $('#lunch').html(lunchtml);
            $('#totalunch').html(total);
        },
        renderdinner: function(){
            var total = 0;
            var dinnerhtml = '';

            this.dinnerlist.each(function(dish) {
                dinnerhtml = dinnerhtml + dish.get('html');
                total += dish.get('calories');
            }, this)
            $('#dinner').html(dinnerhtml);
            $('#totaldinner').html(total);
        },
        rendersnack: function(){
            var total = 0;
            var snackhtml = '';

            this.snacklist.each(function(dish) {
                snackhtml = snackhtml + dish.get('html');
                total += dish.get('calories');
            }, this)
            $('#snack').html(snackhtml);
            $('#totalsnack').html(total);
        },

        render: function() {
            var terms = this.model;
            var wordhtml = '';
            terms.each(function(term) {
                wordhtml = wordhtml + '<li' + ' data-id=' + '"' + term.get('_id') + '"' + ' data-name=' + '"' + term.get('fields')['item_name'] + '"' + ' data-brand=' + '"' + term.get('fields')['brand_name'] + '"' + ' data-calories=' + '"' + term.get('fields')['nf_calories'] + '"' + '>' + "<strong>" + term.get('fields')["item_name"] + '</strong>' + ' (' + term.get('fields')["brand_name"] + ')' + ' - ' + term.get('fields')["nf_calories"] + ' Calories' + '</li>'
            }, this);
            this.$list.html(wordhtml);

        }
    });
    var app = new App();
});

Here is my HTML-

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <title>Food Guide App</title>

    <!-- Bootstrap -->
    <link href="css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="css/main.css">
  </head>
  <body>

    <div class="text-center bg-black">
        <div class="container">
            <div class="row">
                <div class="col-xs-12">
                    <h1>Interactive Food Guide</h1>
                </div>
            </div>
        </div>
    </div>
    <div class="bg-blue">
        <div class="container">
            <div class="row">
                <div class="col-sm-6">
                    <h2>Food Search</h2>
                    <img class="img-responsive" src="img/my-food-guide-plate.jpg" alt="food plate photo">
                    <a name="foodsearch"></a>
                    <h4>Look up food here:</h4>
                    <input type="text" id="searchBox"> <br/><br/>
                    <p id="instruct"></p>
                    <ul class="spacefood" id="listing"></ul>
                    <a href="#foodtrack">Go to food tracking</a>
                    <p>
                        Go to:
                        <a href="#breakfastrack">Breakfast</a>&nbsp; &nbsp;
                        <a href="#lunchtrack">Lunch</a> &nbsp; &nbsp;
                        <a href="#dinnertrack">Dinner</a>&nbsp; &nbsp;
                        <a href="#snacktrack">Snack</a>&nbsp; &nbsp;
                    </p>
                </div>
                <div class="col-sm-6 top-space bottom-space">
                    <img class="img-responsive" src="img/foods.jpg" alt="foods">
                    <a name="foodtrack"></a>
                    <h2>Foods Tracked</h2>
                    <ul class="top-space spacetracked" id="tracked"></ul>
                    <p id="total"><strong> total calories:</strong> <span>0</span></p>
                    <a href="#foodsearch">Go to food search</a>
                    <p>
                        Go to:
                        <a href="#breakfastrack">Breakfast</a>&nbsp; &nbsp;
                        <a href="#lunchtrack">Lunch</a> &nbsp; &nbsp;
                        <a href="#dinnertrack">Dinner</a>&nbsp; &nbsp;
                        <a href="#snacktrack">Snack</a>&nbsp; &nbsp;
                    </p>
                </div>
            </div>
        </div>
    </div>

    <div class="bg-white">
        <div class="container">
            <div class="row">
                <div class="col-sm-6">
                    <a name="breakfastrack"></a>
                    <h1>Breakfast</h1>
                    <ul class="spacetracked" id="breakfast"></ul>
                    <p id="totalbreak"><strong> total calories:</strong> <span>0</span></p>
                    <a href="#foodsearch">Return to food search</a>
                    <p><a href="#foodtrack">Return to food tracking</a></p>
                    <p>
                        Go to:
                        <a href="#breakfastrack">Breakfast</a>&nbsp; &nbsp;
                        <a href="#lunchtrack">Lunch</a> &nbsp; &nbsp;
                        <a href="#dinnertrack">Dinner</a>&nbsp; &nbsp;
                        <a href="#snacktrack">Snack</a>&nbsp; &nbsp;
                    </p>
                </div>
                <div class="col-sm-6">
                    <img class="img-responsive" src="img/breakfast-meal.jpg" alt="breakfast plate photo">
                </div>
            </div>
        </div>
    </div>

    <div class="bg-blue">
        <div class="container">
            <div class="row">
                <div class="col-sm-6">
                    <a name="lunchtrack"></a>
                    <h1>Lunch</h1>
                    <ul class="spacetracked" id="lunch"></ul>
                    <p id="totalunch"><strong> total calories:</strong> <span>0</span></p>
                    <a href="#foodsearch">Return to food search</a>
                    <p><a href="#foodtrack">Return to food tracking</a></p>
                    <p>
                        Go to:
                        <a href="#breakfastrack">Breakfast</a>&nbsp; &nbsp;
                        <a href="#lunchtrack">Lunch</a> &nbsp; &nbsp;
                        <a href="#dinnertrack">Dinner</a>&nbsp; &nbsp;
                        <a href="#snacktrack">Snack</a>&nbsp; &nbsp;
                    </p>
                </div>
                <div class="col-sm-6">
                    <img class="img-responsive" src="img/lunch-meal.jpg" alt="lunch plate photo">
                </div>
            </div>
        </div>
    </div>

    <div class="bg-white">
        <div class="container">
            <div class="row">
                <div class="col-sm-6">
                    <a name="dinnertrack"></a>
                    <h1>Dinner</h1>
                    <ul class="spacetracked" id="dinner"></ul>
                    <p id="totaldinner"><strong> total calories:</strong> <span>0</span></p>
                    <a href="#foodsearch">Return to food search</a>
                    <p><a href="#foodtrack">Return to food tracking</a></p>
                    <p>
                        Go to:
                        <a href="#breakfastrack">Breakfast</a>&nbsp; &nbsp;
                        <a href="#lunchtrack">Lunch</a> &nbsp; &nbsp;
                        <a href="#dinnertrack">Dinner</a>&nbsp; &nbsp;
                        <a href="#snacktrack">Snack</a>&nbsp; &nbsp;
                    </p>
                </div>
                <div class="col-sm-6">
                    <img class="img-responsive" src="img/dinner-meal.jpg" alt="dinner plate photo">
                </div>
            </div>
        </div>
    </div>

    <div class="bg-blue">
        <div class="container">
            <div class="row">
                <div class="col-sm-6">
                    <a name="snacktrack"></a>
                    <h1>Snack</h1>
                    <ul class="spacetracked" id="snack"></ul>
                    <p id="totalsnack"><strong> total calories:</strong> <span>0</span></p>
                    <a href="#foodsearch">Return to food search</a>
                    <p><a href="#foodtrack">Return to food tracking</a></p>
                    <p>
                        Go to:
                        <a href="#breakfastrack">Breakfast</a>&nbsp; &nbsp;
                        <a href="#lunchtrack">Lunch</a> &nbsp; &nbsp;
                        <a href="#dinnertrack">Dinner</a>&nbsp; &nbsp;
                        <a href="#snacktrack">Snack</a>&nbsp; &nbsp;
                    </p>
                </div>
                <div class="col-sm-6">
                    <img class="img-responsive" src="img/snack-meal.jpg" alt="snack plate photo">
                </div>
            </div>
        </div>
    </div>

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

    <!-- Backbone and Underscore -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.1/backbone-min.js"></script>
    <!-- apps functionality -->
    <script src="js/app.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="js/bootstrap.min.js"></script>
    <!-- Firebase -->
    <script src="https://cdn.firebase.com/js/client/2.2.9/firebase.js"></script>
    <!-- BackboneFire -->
    <script src="https://cdn.firebase.com/libs/backbonefire/0.5.1/backbonefire.min.js"></script>
  </body>
</html>

Upvotes: 1

Views: 97

Answers (1)

Lee
Lee

Reputation: 2730

You need to have diferent URLs for your collections.

var Foods = Backbone.Firebase.Collection.extend({
    model: Food,
    url: "https://blinding-torch-8751.firebaseio.com/foods",
});

var Breakfast = Backbone.Firebase.Collection.extend({
    model: Food,
    url: "https://blinding-torch-8751.firebaseio.com/breakfasts",
});

Unrelated, but when doing Backbone.Collection.create you should pass attributes, not a model. http://backbonejs.org/#Collection-create Here is an example:

this.foods.create({
  id: foodid,
  title: item_name,
});

Upvotes: 1

Related Questions