1

I am practising with vainilla JS, fetching some data from a public API, and manipulating the DOM with them.

I am finding a problem i am not sure how to solve. The object has some null values in some fields , but other times that field contain some information. When I run a loop over it, it always breaks when it reaches one field with a null value.

I would like to know what the best approach should be.

One might be to "clean" the null values from the object, and store the "new cleaned" object in a variable . But guess that´s not the way to go if the API were big.

My second idea would be to include an if condition in the loop, saying to jump to the next one, if the value found is === null , something like this :

function createSomeCards(myObject) {
       for (let i=0; i < myObject.lenght; i++) {
    if (value === null) { i = i+1 } else { i = i }
    here would go the rest of the code to build the cards

i don`t know if that is the approach (even if my code is waz wrong), or should be different. The object has an structure similar to this :

 myObject = [
    {
        "Habitat Impacts": "Area closures ",
        "Image Gallery": [
            {
                "src": "anImage.jpg",
                "alt": "some text",
                "title": "more text"
            },
            {
                "src": null,
                "alt": "additional text",
                "title": "a title here"
            },
            {
                "src": "otherImg.jpg",
                "alt": "imgInfor",
                "title": null
            }      
        ],
        "Management": null,
        "Scientific Name": "Urophycis tenuis",
        "Species Illustration Photo": {
            "src": null,
            "alt": "Illustration",
            "title": ""
        },
        "Ecosystem Services": null,   
        "Servings": "1",
        "last_update": "05/19/2021 - 13:04"
    }]

I update the comment with the JS code in which I am finding the issue with the Null values

function createCards(myObject) {
    let cardContainer = document.getElementById('cardContainer');
    
    for (let i = 0; i < myObject.length; i++) {

    
            
        aInfoButtonLeft.onclick = function () {
            let divSlidAct = document.getElementById('sliderImg')
            let imgSlidAct= document.createElement('img');
            imgSlidAct.setAttribute('src', myObject[i]['Image Gallery'][i]['src']);
            imgSlidAct.append(divSliderActive);
        }

    }
}
notADevYet
  • 307
  • 2
  • 13
  • Did you try **continue** keyword? `if(value === null) {continue}` – Muhammet Yunus Jul 18 '21 at 13:04
  • nope, i did not know that keyword. Thanks for it. I will try it :) Just one questions, let´s say it works...should I include that in every function with a loop over the Object ...or would be other way to avoid having to repeat those lines whenever I build different functions (thinking in a function to build a table in one file, creating a slider with Imgs in other file, etc...) – notADevYet Jul 18 '21 at 13:07
  • 1
    Note that your function loops through an **array**, not an object (or it will if you fix the spelling of `length` :-) ). See [this question](https://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object) for how to loop through an object. – T.J. Crowder Jul 18 '21 at 13:08
  • Continue keyword allows us to skip a specific element in a loop. [Reference](https://www.w3schools.com/jsref/jsref_continue.asp) | As for your question, I have to know your function and your goal with it clearly to answer. Can you share? – Muhammet Yunus Jul 18 '21 at 13:20
  • @T.J.Crowder ups...that Length :D ---thanks! ..i will have a look to that question. Although now I got a bit confused... when I was creating the funtion for the table, I did a for loop like the one above, and getting the value of some fields like myObject[i].images[i].title, for example ... isn´t that the right way? – notADevYet Jul 18 '21 at 13:21
  • @notADevYet - No, is isn't. – T.J. Crowder Jul 18 '21 at 13:22
  • @MuhammetYunusTunca My goal would be to get the images from the myObject[i]['Image Gallery'][i]['src'] , So i can append them to a DOM element. But when the loop reaches one src = Null, it stops. My idea is to get a solution that would help me , not only with the "null" from that field, but with others. ...continues – notADevYet Jul 18 '21 at 13:27
  • sorry....it seems I dont know how to mark up the code in comments. I will update it in my question – notADevYet Jul 18 '21 at 13:31
  • @T.J.Crowder ok, thanks for the answer. Then i am really wrong. But looping like that, I am getting the values I need. What would be the right way or doing the same? – notADevYet Jul 18 '21 at 13:38
  • @notADevYet Please try to change this line: `imgSlidAct.setAttribute('src', myObject[0]['Image Gallery'][i]['src']);` | According to your object's structure you have to call **myObject[0]** – Muhammet Yunus Jul 18 '21 at 13:42
  • @notADevYet If you write your codes in a snippet that will be much better. – Muhammet Yunus Jul 18 '21 at 13:46
  • @MuhammetYunusTunca but then i would get only the value of the first element, right? , the object contains 150 elements , I just wanted to give a representation . `myObject[i= from 0 to 150 ] ` Anyway , that line is working ...but when it reaches a `src = null` (and the first one is at myObject[5] , console gives me an error and loops stops – notADevYet Jul 18 '21 at 13:49
  • @notADevYet Then you have to do two nested loops. First one loops through `myObject [0,1,2 ...]` and the second one loops through `myObject[i]['Image Gallery'][0,1,2 ...]` – Muhammet Yunus Jul 18 '21 at 13:55

2 Answers2

2

I am going to leave my orignal answer under this one because I think it still relevant.

you have an array in an array and you are not looping over the second array "Image Gallery". Adding a second loop lets you get all the images.

I added a check to see if the src was null. this should stop any errors you get about src being null.

function createCards(myObject) {
    let cardContainer = document.getElementById('cardContainer');

    for (let i = 0; i < myObject.length; i++) {

        for (let x=0; x < myObject[i]["Image Gallery"].length; x++) {

                if (myObject[i]['Image Gallery'][x]["src"] === null) {
                    // the source is empty do nothing
                }else{
                    aInfoButtonLeft.onclick = function () {
                    let divSlidAct = document.getElementById('sliderImg')
                    let imgSlidAct= document.createElement('img');
                    imgSlidAct.setAttribute('src', myObject[i]['Image Gallery'][x]["src"]);
                    imgSlidAct.append(divSliderActive);
                }
            }
        }
    }
}

ORIGNAL ANSWER

You have 2 1 issue.

  1. you have an array in an array and you are not looping over the second array "Image Gallery"

2. the 'src' field is an attribute of an object and not an index of an array.

The fact that you have null values doesn't matter. the loop will continue.

See the code below with comments.

let myObject = [
{
    "Habitat Impacts": "Area closures ",
    "Image Gallery": [
        {
            "src": "anImage.jpg",
            "alt": "some text",
            "title": "more text"
        },
        {
            "src": null,
            "alt": "additional text",
            "title": "a title here"
        },
        {
            "src": "otherImg.jpg",
            "alt": "imgInfor",
            "title": null
        }      
    ],
    "Management": null,
    "Scientific Name": "Urophycis tenuis",
    "Species Illustration Photo": {
        "src": null,
        "alt": "Illustration",
        "title": ""
    },
    "Ecosystem Services": null,   
    "Servings": "1",
    "last_update": "05/19/2021 - 13:04"
}];

//loop over my object
for (let i=0; i < myObject.length; i++) {

//loop over the image gallery
  for (let x=0; x < myObject[i]["Image Gallery"].length; x++) {
    console.log("src: " + myObject[i]["Image Gallery"][x].src); //notice it .src and not ["src"]
    console.log("alt: " +myObject[i]["Image Gallery"][x].alt);
    console.log("title: " +myObject[i]["Image Gallery"][x].title);
    
    //I commented out this section so the snippet would work 
   /*
    aInfoButtonLeft.onclick = function () {
        let divSlidAct = document.getElementById('sliderImg')
        let imgSlidAct= document.createElement('img');
        imgSlidAct.setAttribute('src', myObject[i]['Image Gallery'][x].src);
        imgSlidAct.append(divSliderActive);
   */
    }

  }
RyDog
  • 1,169
  • 1
  • 9
  • 12
  • first of all...thanks a lot for taking the time and the instructive answer. The thing is, with that code i had, I was getting the images of the first 3 or 4 elements in the Object , but getting a console error `Uncaught TypeError: Cannot read property '2' of null at HTMLAnchorElement.aInfoButtonLeft.onclick ` the moment the loop reached the first element with the attribute Null for the Src property ... not trying to contradict or anything. Just trying to learn – notADevYet Jul 18 '21 at 14:01
  • 1
    All good, ill upodate answer to counter the error you have just described – RyDog Jul 18 '21 at 14:03
  • 1
    @notADevYet i updated the answer, let me know if thats what you were hoping for – RyDog Jul 18 '21 at 14:16
  • 1
    there was a small syntax error, fixed it now. – RyDog Jul 18 '21 at 14:21
  • hey, thanks again! . I tried, and it works but I found another /or similar problem ... It have found some attributes in which `'Image Gallery' : null ` and some with `'image Gallery' : { 'src' : 'anyUrl' , 'alt' : 'someValue' } ` (note that those are different than `'image gallery' : [ { } ] `) so when I reach those, the problem is still the same. Any idea how to solve those? – notADevYet Jul 18 '21 at 14:34
  • 1
    It is prob best to ask a new question with full example of problem data and code. If you tag me in comments i'll have a go at it. – RyDog Jul 18 '21 at 14:37
  • I will do it like in an hour or so. Thanks very much RyDog – notADevYet Jul 18 '21 at 14:39
  • i opened a new question here : https://stackoverflow.com/questions/68430477/how-to-avoid-null-values-in-a-json-object-when-looping-over-it?noredirect=1#comment120937053_68430477 – notADevYet Jul 18 '21 at 15:26
1
  1. Please change the question title, because you're not looping over an object where there's some null values, but you're looping over an array that only has non-null values in your example. The item of that loop can have a property that is sometimes null. That's a different issue.
  2. You asked about the best approach.

    1. "clean" the null values and store the "new cleaned" object in a variable

      This is not necessary and yes, this would blow up your memory usage and would consume time

    2. include an if condition in the loop, saying to jump to the next one, if the null value found

      if (item.property === null) {
        // jumping to the next item of the loop
        continue;
      }
      
      // do the processing
      

      You can either jump to the next (continue) or you don't do the processing for that item (you do the processing only if not null) like this:

      if (item.property !== null) {
        // do the processing
      }
      
    3. You could even be safer if checking properties by hasOwnProperty() like here: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

    4. I recommend using functional programming and filtering the array by using https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter like this - this results in a much clearer code:

      // for this you could also use myObject.forEach(), but that's not the question here
      for (let i = 0; i < myObject.length; i++) {
      
        // filtering image gallery for items that ...
        myObject[i]['Image Gallery'] //
          // have a non-null src
          .filter(item => item.src !== null) //
          // and do for each item that following...
          .forEach(item => {
            console.log('src: ' + item.src); //notice it .src and not ["src"]
            console.log('alt: ' + item.alt);
            console.log('title: ' + item.title);
          });
      }
      
Janos Vinceller
  • 1,208
  • 11
  • 25
  • First of all, thanks big time for the effort made in your reply. Is one of those that helps to keep on learning. Title adjusted.But that leads me to a question (maybe a stupid one) Then , if i am understanding well ,the difference between an object and an Array, is mainly conceptual, right?An array can be formed by several objects,and an object can contain different arrays, is that correct? So far, i thought that beside that conceptual definition, objects and arrays were also structured differently , being `myObject = [ {}, {} ] ` , and Arrays more like `myArray = { " " : "", " " : " " }` – notADevYet Jul 18 '21 at 22:04
  • 1
    You can think of an array as a container of primitives or objects. You'd initiate one like `myArray = [];` or `myArray = new Array();` or incl. data like `myArray = [ 1, 2, 3 ];`. An array wouldn't contain methods, but having the standard array methods like `shift()`, `push()` etc. An object would mostly be data and code together, where 1) the single pieces data are somehow coupled together (should be!) 2) contain methods to act on those. In modern JS code you often use simple data objects, that contain no code. Data/methods are bound to properties like this: `myObject = { data1: '...' }` – Janos Vinceller Jul 18 '21 at 22:24
  • Thanks again for the educative answer. It encourages to keep larning. – notADevYet Jul 19 '21 at 09:24