-3

I want to make a more elegant solution for my loop. How to use a function instead of all the "else if" statements, they are so many. There are several variables to take into account. The statement presents different icons on a map in laravel project.

The loop:

for (i = 0; i < locations.length; i++) {
  end = new Date(locations[i][6]);
  date1 = new Date(locations[i][4]);
  todaysdate = new Date(ldstr);
  upcomingdate = new Date(locations[i][5]);
  finisheddate = new Date(locations[i][9]); // Randomiserad ikon om två eller fler på samma ort.
  var newLat = locations[i][1] + (Math.random() - .15) / 20;
  var newLng = locations[i][2] + (Math.random() - .15) / 20;
  if ((locations[i][6]) || (locations[i][7]) == 0) { // closed or not public
    var marker = new L.marker([newLat, newLng], marker3);
    marker.url = locations[i][8];
    marker.bindPopup(locations[i][0]);
    //  marker.addTo(map);  //Visas ej för stängd 
    marker.on('click', function() {
      window.location = (this.url);
    });
    marker.on('mouseover', function(e) {
      this.openPopup();
    });
    marker.on('mouseout', function(e) {
      this.closePopup();
    });
  } else if (todaysdate > finisheddate) { // finished
    var marker = new L.marker([newLat, newLng], marker2);
    marker.url = locations[i][8];
    marker.bindPopup(locations[i][10]);
    marker.addTo(map);
    marker.on('click', function() {
      window.location = (this.url);
    });
    marker.on('mouseover', function(e) {
      this.openPopup();
    });
    marker.on('mouseout', function(e) {
      this.closePopup();
    });
  } else if (todaysdate > date1) { // signups closed
    var marker = new L.marker([newLat, newLng], marker2);
    marker.url = locations[i][8];
    marker.bindPopup(locations[i][12]);
    marker.addTo(map);
    marker.on('click', function() {
      window.location = (this.url);
    });
    marker.on('mouseover', function(e) {
      this.openPopup();
    });
    marker.on('mouseout', function(e) {
      this.closePopup();
    });
  } else if (todaysdate < upcomingdate) { // upcoming
    var marker = new L.marker([newLat, newLng], marker3);
    marker.url = locations[i][8];
    marker.bindPopup(locations[i][11]);
    marker.addTo(map);
    marker.on('click', function() {
      window.location = (this.url);
    });
    marker.on('mouseover', function(e) {
      this.openPopup();
    });
    marker.on('mouseout', function(e) {
      this.closePopup();
    });
  } else {
    var marker = new L.marker([newLat, newLng], marker1); // signups open
    marker.url = locations[i][8];
    marker.bindPopup(locations[i][0]);
    marker.addTo(map);
    marker.on('click', function() {
      window.location = (this.url);
    });
    marker.on('mouseover', function(e) {
      this.openPopup();
    });
    marker.on('mouseout', function(e) {
      this.closePopup();
    });
  }; // end for loop

The database loop:

@foreach ($data as $i)
              [ "{{ $i->name }}  " + "i " + "{{ $i->contact_city }}" +  " <br>" + "{{ $i->date }}" + "   Anmälda: " + 
              "{{ $i->signups_count }}"+ " <br>"  + "Anmälan stänger " + "{{ $i->signups_closing_date }}" , 
              {{ $i->lat }},{{ $i->lng }},0, "{{ $i->signups_closing_date }}" , "{{ $i->signups_opening_date }}" ,  
              "{{ $i->closed_at }}" , "{{ $i->is_public }}",'/app/competitions/'+ "{{ $i->id }}" + '/information', "{{ $i->date }}", 
              "{{ $i->name }}  " + "i " + "{{ $i->contact_city }}"+ " <br>" + "{{ $i->date }}" + " Avslutad/Genomförd", 
              "{{ $i->name }}  " + "i " + "{{ $i->contact_city }}" + " " + "{{ $i->date }}" +  " <br>" + "Anmälan öppnar " + 
              "{{ $i->signups_opening_date }}","{{ $i->name }}  " + "i " + "{{ $i->contact_city }}"+ " <br>" + "{{ $i->date }}" + 
              " Anmälan stängd"],
          @endforeach 
    ];
                var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
                var osmAttrib='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                var osm = new L.TileLayer(osmUrl, {attribution: osmAttrib});
                var map = new L.Map('map').addLayer(osm).setView([59.55,12.26], 5);
                map.options.minZoom = 3;
                map.options.maxZoom = 14;
                var t=new Date();
                var visa;
                var ldstr=t.toLocaleDateString(); // Today's date.

This is the loop that executes every time the map is accessed.

  • 1
    "Using a function instead of the if/else statements", that makes little sense. But the code blocks _inside_ those if/else branches, where you are always doing the same thing, only with slightly different values - those are of course a prime candidate for replacing with a function. – CBroe Jan 18 '22 at 16:13
  • extract them into seperate functions. – Bulent Jan 18 '22 at 16:13
  • The code you add for click, mouseover and mouseout events, is always exactly the same. So that could have been placed _after_ these if/else to begin with. (Unless you had a case, where in some loop iterations you would not create a marker at all; but since the last is a simple else without any condition, that does not appear to be the case.) – CBroe Jan 18 '22 at 16:15

1 Answers1

0

Move the common code out of the if...else structure, such as setting up the event listeners.

For where there is variation, create an array with all the variations for a given argument/index, and pick one dynamically from that array based on a state.

That state can be set up by executing the if conditions in a conditional expression, each time associating a state (ranging from 0 to 4).

Also use the for..of syntax and declare all your variables with var, let or const.

for (let location of locations) {
  var end = new Date(location[6]);
  var date1 = new Date(location[4]);
  var todaysdate = new Date(ldstr);
  var upcomingdate = new Date(location[5]);
  var finisheddate = new Date(location[9]); 
  var newLat = location[1] + (Math.random() - .15) / 20;
  var newLng = location[2] + (Math.random() - .15) / 20;
  
  var state = location[6] || (location[7] == 0) ? 0
            : todaysdate > finisheddate ? 1
            : todaysdate > date1 ? 2
            : todaysdate < upcomingdate ? 3
            : 4;
            
  var marker = new L.marker([newLat, newLng], [marker3, marker2, marker2, marker3, marker1][state]);
  marker.url = location[8];
  marker.bindPopup(location[[0, 10, 12, 11, 0][state]]);
  if (state) marker.addTo(map);
  marker.on('click', function() {
    window.location = this.url;
  });
  marker.on('mouseover', function(e) {
    this.openPopup();
  });
  marker.on('mouseout', function(e) {
    this.closePopup();
  });
}; // end for loop
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thanks a lot! Well, it is absolutely nice coding but there is a thing. In the original loop in the very first if... if the competition was deleted (locations[i][6]) || (locations[i][7]) == 0) it shall not show a marker at all. Now it shows marker1. Maybe you can see how to modify? – Ralph Hoglund Jan 19 '22 at 13:36
  • I had commented out " // marker.addTo(map); //Don't show marker for deleted competition" earlier – Ralph Hoglund Jan 19 '22 at 13:39
  • This translates to `if (state)` in my code. `state` has the value 0 when `(location[6]) || location[7]) == 0`, so then `marker.addTo` is not called. But I see I translated that condition in the wrong way. I updated that just now moving the parentheses. Can you check again? – trincot Jan 19 '22 at 13:41
  • Thanks a lot my friend! I'll check – Ralph Hoglund Jan 19 '22 at 13:44
  • I can't see any changes? No difference – Ralph Hoglund Jan 19 '22 at 13:50
  • 1
    It's in the line `state =` – trincot Jan 19 '22 at 13:54
  • Ok, my mistake, I saw it and now it works just fine! Thanks a million for your help. – Ralph Hoglund Jan 19 '22 at 14:04
  • I wonder, if I would like to incorporate another marker that shows "late signups" that is possible after "signups_closed". That would mean to insert "{{ $i->allow_signups_after_closing_date }}" , in the @foreach ($data as $i)-loop and add a var latesignup = new Date(location[X]);? But it is not a date, it is a "1" in the table column in the database. All others are dates and/or names. – Ralph Hoglund Jan 24 '22 at 12:05
  • I have added the database loop which is the foundation of all variables. See above. – Ralph Hoglund Jan 24 '22 at 12:09
  • Correction, is_public is also a "1" in the table, if 1 the marker is visable on the map otherwise not. – Ralph Hoglund Jan 24 '22 at 12:29
  • If you have a new problem, then please ask a new question. The comment section is not intended for new questions. Please be aware that questions should be accompanied by your attempt, and the problem with it. – trincot Jan 24 '22 at 12:41
  • Hi. Got another small problem. When I create a competition and chose the upcomingdate to be today I'm getting the marker3 instead of marker1. Can that be changed so I'm getting marker1 for today. I will also wish you all the luck in the unfortunate war that strikes you. I hope it ends as soon as possible. – Ralph Hoglund Jun 07 '22 at 16:39
  • That is something that would also happen with your original code. So it seems a different question then. You can change `todaysdate < upcomingdate` with `<=`, but be aware that `todaysdate` is not midnight, so you should then strip the hours, days, minutes, ...etc from it. But that is a different question that you can find on this site. – trincot Jun 07 '22 at 16:55
  • Well, the <= didn't make any difference. – Ralph Hoglund Jun 07 '22 at 21:15
  • 1
    I know, you have to [reset](https://stackoverflow.com/questions/3894048/what-is-the-best-way-to-initialize-a-javascript-date-to-midnight) the hour/minute/second part of the `upcomingdate` date. So, do [upcomingdate.setHours(0, 0, 0, 0)` before doing any of those `if` statements. – trincot Jun 08 '22 at 05:16
  • Yes, thanks a lot, that worked really well. You've been very helpful my friend! – Ralph Hoglund Jun 09 '22 at 08:51