Lyubomir
Lyubomir

Reputation: 311

Trying to use javaScript setInterval to alternate content but it does not work

i am trying to alternate the text of some elements and pass a parameter as shown in MDN. However, it doesn't work. Is the problem that i am messing jQuery and pure JavaScript? This is my HTML, this is my CSS and this is the JavaScript.

$(function() {
    $("#top_navbar").on("show.bs.collapse", function() {
        $("#top_navbar > ul").css({
            "background-color": "black",
            "text-align": "center"
        });
    });

    $("#top_navbar").on("hidden.bs.collapse", function() {
        $("#top_navbar > ul").css("background-color", "transparent");
    });

    var headerStatus = 0;
    var h1Header = $("#header_content > div:first-of-type").filter("h1");
    var h3Header = $("#header_content > div:last-of-type").filter("h3");
    var firstParaHeader = $("#header_content > div:first-child").filter("p:first-of-type");
    var lastParaHeader = $("#header_content > div:first-child").filter("p:last-of-type");

    function changeHeaderContent(num) {
        switch (num) {
            case 0:
                h1Header.innerHTML = "The Trio";
                h3Header.innerHTML = "Creative design studio";
                firstParaHeader.innerHTML = "Creating the brand experience you & your audience deserve with Inbound Marketing.";
                lastParaHeader.innerHTML = "We already work with over 130 clients.";
                headerStatus = 1;
                break;
            case 1:
                h1Header.innerHTML = "Create Brand";
                h3Header.innerHTML = "our true area of expertise";
                firstParaHeader.innerHTML = "We create simple, beautiful, and conversion focus designs for your customers.";
                lastParaHeader.innerHTML = "And delivered more than 210 design projects.";
                headerStatus = 0;
                break;
        }
    }
    setInterval(changeHeaderContent, 5000, headerStatus);
});

Upvotes: 0

Views: 292

Answers (2)

Scott Marcus
Scott Marcus

Reputation: 65795

Your setInterval instruction is only actually being executed once. At the point in time, headerStatus is 0, so that's the value that is always used every time changeHeaderContent is invoked.

In order to correctly pass your value to the function so that the value is updated upon each invocation, your syntax needs to be adjusted so that you call a function that calls the function you really want invoked with the parameter you need passed to that. This will cause a closure to be formed around headerStatus and you won't lose its value upon each invocation.

Adjusting the syntax allows for changeHeaderContent to close over headerStatus and then you reap the benefits of the closure.

setInterval(function(){
   // Call changeHeaderContent and pass the value of headerStatus to it:
   changeHeaderContent(headerStatus);
}, 5000);

Here's an example of how the two different versions of the syntax result in different results (see inline comments for explanations):

(function(){
  var headerStatus = 0;

  function changeHeaderContent(num) {
    
    // Because headerStatus is used in this nested function and because it was declared
    // in a higher order function, there is a closure around headerStatus (this makes
    // headerStatus a "free variable"). However, the closure will only cause side-effects
    // if this nested funciton "outlives" its parent function's lifetime.
    
    switch (num) {
      case 0:
        headerStatus = 1;
        break;
      case 1:
        headerStatus = 0;
        break;
      }
    console.log("headerStatus is now: " + headerStatus);
  }
  
  // Now that the nested function has termintated and we are back in the higher order
  // function's scope, the following syntax runs without any closures. Whatever the value of
  // headerStatus is, that value will be passed to the next invocation of changeHeader.
  
  // Based on the code, the value of headerStatus will be 0 (changeHeaderContent hasn't 
  // executed yet) and so changeHeaderContent will change it to 1. BUT... each time 
  // changeHeaderContent runs it won't be passed the updated value of headerStatus, this
  // syntax just passes it once and that original value is used for each subsequent invocation.
  
  // So, every time chagneHeaderContent is run, it's run with the original value of 
  // headerStatus, which was 0. Therefore, each invocation of changeHeaderContent will 
  // change it to 1.
  setInterval(changeHeaderContent, 1000, headerStatus);

}());

And, now with the suggested code:

(function(){
  var headerStatus = 0;

  function changeHeaderContent(num) {
   
    switch (num) {
      case 0:
        headerStatus = 1;
        break;
      case 1:
        headerStatus = 0;
        break;
      }
    console.log("headerStatus is now: " + headerStatus);
  }
  

  setInterval(function(){
    // Because the function that will be executed every 5 seconds contains a reference to
    // headerStatus (a free variable) and that function WILL outlive the higher order function
    // where headerStatus was declared, it forms a closure around it and EACH time the 
    // function runs, it will use the last known value of headerStatus, thus allowing the
    // old value to be used in determining the new value.
    changeHeaderContent(headerStatus)
  }, 1000);

}());

Upvotes: 1

Lesotto
Lesotto

Reputation: 84

I think Scott Marcus is right with his code snippet. If you console.log your cases, you will notice that the parameter is obviously sent by value and not by reference, thus you are always ending with case 0. This way the function is passed as a closure and a reference to headerStatus is passed with it, rather then being read just one at the first interval.

so:

setInterval(function () {
    changeHeaderContent(headerStatus);
},5000);

And also for element content, you should probably use jQuery methods like text() or better html() so:

case 0:
    h1Header.html("The Trio");
    h3Header.html("Creative design studio");
    ...

case 1:
    h1Header.innerHTML = "Create Brand";
    h3Header.html("our true area of expertise");
    ...

And this way for all elements you want to change. And also this about getting elements via jQuery, I would suggest using context #header_content:

var h1Header = $('h1', $("#header_content"));
var h3Header = $('h3', $("#header_content"));

I have tested it locally like this and it works for me..

Upvotes: 1

Related Questions