2

Maybe I'm structuring this code wrong (first time working with Javascript) but I want to take user input and search an array of arrays to check if an array with that name exists.

I first tried using the eval() function which I've been told isn't good but it works when there is a match, failing when a match that doesn't exist though.

The basic premise of the program is there is an array containing locations which are subsequently arrays containing food items. The user enters the name of a food item and where they want to put it and it will create an object of food, insert that object into the right location within the arrays, and also input the item onto a list displayed in html.

Here's all the code so far:

var fridge = [];
var freezer = [];
var pantry = [];

var locations = [fridge, freezer, pantry];


function Food(name, location, locationName){
    this.name = name;
    this.location = location;
    this.locationName = locationName;
    this.displayName = function(){
        alert(this.name);
    };
};
function createFood(){
    var name = prompt("Enter the items name:");
    var locationName = prompt("Enter a location to store it:")
    var location = eval(locationName);

    while(locations.indexOf(location) == -1){
        alert("This is not an actual location.");
        locationName = prompt("Please enter another location:");
        location = eval(locationName);
    };

    var x = new Food(name, location, locationName)

    function insertFood(Food){
        var a = locations.indexOf(Food.location);
        locations[a].push(Food);

        var list = document.getElementById(Food.locationName + "_items");
        var li = document.createElement("li");
        li.innerHTML = Food.name;
        list.insertBefore(li, list.lastChild);
    };

    insertFood(x);
};

Please let me know if this is structured wrong cause this was my idea for structuring at first glance.

Thanks!

0

2 Answers 2

1

As suggested above, it would be best to make locations an object, so that you can have a key (a string) pointing to the array with the same name.

    var fridge = [];
    var freezer = [];
    var pantry = [];

    var locations = {
        "fridge":fridge, 
        "freezer":freezer, 
        "pantry":pantry
    };

The benefit of this is that you don't need to have a locationName, since it never really comes into play. All you would need is to check if the locations object has a property by the same name as the user input, using the native hasOwnProperty function. Something like:

    if(!locations.hasOwnProperty(userInputLocation)) 
        alert("That is not a designated location");

Then your Food constructor also becomes simpler, and needs only name and location properties:

    function Food(name, location){
        this.name = name;
        this.location = location;
    }

You can also then call any specific location directly by its name (if you're going to declare it globally as you did in your code), or more appropriately (if you declare the arrays inside the object as in SGD's code) by locations[location], where location is just a string holding either "freezer" or "pantry" or "fridge". You can also call the array via locations[someFood.location].

Anyway I am not much for prompts and alerts (let alone eval), so I created a jsBin using input fields, you can check it out here: http://jsbin.com/pamoquwuhu/1/edit

edited to add: If the goal is that you later want to find food by its name in all the locations it is saved in, it would be best to add/push foodObj.name instead of the whole foodObj in locations[location]. Then you can use the native for(property in object) loop on the locations object to see where all a given food might be stored, and push it into a results array. So your findFood function might contain the following (assuming food is the user input string of of food name to search for:

    var results = [];

    for(var loc in locations){ // loops through the property names in `locations`
        if(locations[loc].indexOf(food)>=0)
            results.push(loc);
    }

    if(!results.length){
        alert(food+' was not found');
    else
        alert(food+' was found in '+results.toString());

Assuming the same food can be stored in multiple locations and that you want to find a given food by its name, your food object's location property would become less important (or possibly useless).

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much for the help. Definitely learning a ton of stuff I didn't know from this. Just a few quick questions: What is the purpose of e.preventDefualt() in this situation and what are the advantages of querySelector() over getElementById()?
e is the name I gave to the first argument of my event handler function - in JS this is always the event itself. The event has all sorts of properties (mouse position, event type, target etc) - and you can read about it here: developer.mozilla.org/en/docs/Web/API/Event.Since I used a form in my example, the default action on the "click" submit event is to submit the form to the URL specified in the form.
...But I don't want to submit to another URL, I only used the form so that I could use the input values (and most of all so that pressing "enter" after filling the fields would also trigger the handler just like a click) - so I have to prevent this default action using e.preventDefault(). Whenever there is a default action associated with an event (like going to a different page or something) and you want to override that, event.preventDefault() is your friend. Otherwise the code in the handler will run and then continue with the default action.
...Also, querySelector helps to select elements by their CSS selector. In case of just IDs being used, getElementById is actually faster in selecting the element. I'm just used to querySelector since you can pass strings with spaces, classes and attributes into it so it's used much more.
0

You are using Food as function/constructor and as parameter name (that should not be the issue however but can cause trouble later) and you are never calling insertFood. Also locations should rather be object than array so that you can access the sub arrays as you do in your code.

var locations = {fridge : [], freezer:[], pantry:[]];


function Food(name, locationName){
    this.name = name;
    this.locationName = locationName;
    this.displayName = function(){
        alert(this.name);
    };
};
function createFood(){
    var name = prompt("Enter the items name:");
    var locationName = prompt("Enter a location to store it:")

    while(locationName in locations){
        alert("This is not an actual location.");
        locationName = prompt("Please enter another location:");
    };

    var x = new Food(name, locationName)

    function insertFood(food){
        locations[food.locationName].push(food);

        var list = document.getElementById(food.locationName + "_items");
        var li = document.createElement("li");
        li.innerHTML = food.name;
        list.insertBefore(li, list.lastChild);
    };
    // call the method now?
    insertFood(x);
};
createFood();

2 Comments

Thanks but yeah the insertFood(x) was there before I just seemed have to misplaced it when copying over the code. Also I had created insertFood outside of the createFood function originally and then migrated it so maybe now I should change the parameter name.
Yes, I just saw that while I changed locations to object the code was not fully updated, it should be now.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.