Switching text between two strings

Hi.
I am trying to switch a text in a text box between two strings, like change the text to one another after 5 seconds and repeating it.
I am using setInterval() with hide and show animation,
and my code looks like:

const string1 = "Hi";
const string2 = "Hello";

$w.onReady(() => {
    setInterval(changeText, 5000);
} 

const changeText = () => {
    if ($w("#textbox").text === string1) {
    
        // Hide the text box first so users cannot see the text changing
        $w("#textbox").hide("fade", { duration: 500 });
        // Change the text while it is not visible
        $w("#textbox").text = string2;
        // Show the text box again so users can see the text changed
        $w("#textbox").show("fade", { duration: 500 });
        
     } else if ($w("#textbox").text === string2) {
     
         $w("#textbox").hide("fade", { duration: 500 });
         $w("#textbox").text = string1;
         $w("#textbox").show("fade", { duration: 500 });
         
     }
    
}

The text fades out when the text is “Hi” as I intended but the text is gone away for 5 seconds and then changed text, “Hello”, fading in. And it changed back to “Hi” right away.

What I want is fade the text out and change the text and show the changed text right away but with fade in/out animation so it looks like it keeps changing the text every 5 seconds but my code does not work as I expected.

Can anyone help? Thanks.

hide() and show() are promises, and timing is important.
Try:

 $w("#textbox").hide("fade", { duration: 500 })
 .then(()=> {
 //change the text
 // add the show() function
 })
 //do the same for else if

Also, don’t forget that the fade effect has also a delay option.
Change as needed:
FadeEffectOptions

let fadeOptions = {
  "duration":   2000,
  "delay":      1000
};

$w("#myElement").show("fade", fadeOptions);

Thanks a lot! If you don’t mind, what do you think I can do for toggling 3 elements not 2? It becomes much more complicated and I feel lost now.

@cto86752 I like my code to be short, so if I wanted to switch between many texts, I wouldn’t use if conditions at all, but do something like this:

let texts = [
"text1",
"text2",
"text3",
"text4"
];
let numberOfTexts = texts.length;
let counter = 0;
//and then $w.onReady(), setinterval etc... and inside the changeText() function:

const changeText = () => {
let textIndex = counter % numberOfTexts; //using modulo will let you loop again to the beginning of the array.
$w("#textbox").text = texts[textIndex];
//hide() and show() as usual
counter++;
}

@Jim Park

Whoa! Thought I could solve this simple puzzle in a few minutes.
Timers are tricky, and it took me way longer than expected … but I got there. LMAO.

There is a logic problem with your code - take a look at this pseudo code:

if ($w("#textbox").text === string1) {
        // hide
        $w("#textbox").text = string2;
        // show
        
} else if ($w("#textbox").text === string2) { // this will always be the case ... you just changed it above 
        // hide
        $w("#textbox").text = string1;
        // show
}

So you’d always execute both conditions instead of one or the other.

That aside, the more interesting part:
Your code failed because you’re commanding three commands - that take about 1 second to complete - in a handful of milliseconds, and so only the first command gets executed properly (hide/fade):

$w("#textbox").hide("fade", { duration: 500 });
$w("#textbox").text = string1;
$w("#textbox").show("fade", { duration: 500 });

You are expecting synchronous execution of your commands.
So you’re expecting for JS to “hide” the textbox and only when such “fade” is completed 500 ms later, you expect JS to continue to the next line and only then change the textbox, and when that is completed, only then to move to the third line and do a show/fade of the textbox.

Instead, what is really happening is asynchronous execution:
You’re calling the hide/fade functions which are promises … they start executing in the background while JS instantly moves to the next line to change the textbox content (creating another promise) and then JS instantly moves to the next line to request show/fade functions (yes, more promises). The show/fade promise cannot execute properly because JS is still busy doing the 500 ms hide/fade function.

So you have the correct synchronous logic for these steps, but for proper JS code to execute the way you intent to, you must do something different - handle the promises properly (as @J.D. suggests with .then) or use setTimeout and a function for each intended step. Like you, I prefer synchronous execution of the main function, so I rolled with “await” and setTimeout (didn’t need await afterall).

You can write those three steps into separate functions:
hide/fade … function hideTextBox () (in my example)
change text … function change1 () and change2() (one for each case - Hi/Hello)
show/fade … function showTextBox ()

Then you can control execution times of these three functions with the native JS comand “setTimeout.”

I left the console logs in there - if you increase the timing, you can see in slow motion how the sync code executes and how the results of the asynchronous promises roll in while the changeText() function executes the whole thing almost instantly.

Hope it helps. If it does - you’re welcome.

const string1 = "Hi";
const string2 = "Hello";
var counter = 0;

$w.onReady(() => {
    setInterval(changeText, 5000);  
})

async function changeText () {
 
    counter ++;
    console.log( "[ " + counter + " ] " + "===================================================================================================");
    console.log("counter % 2 = " + (counter % 2)  );

    hideTextBox();  // takes 500 ms to complete

 if ( counter % 2 ) {  // "counter modulo 2"?  => "1" or "true" means odd number
        console.log("Mod case 1: Hi => fade and change to Hello ");
        console.log("Request delayed changing to Hello");
        setTimeout(change1, 800);       // wait for 500 ms fade to finish before you execute textbox change
    }  

 if ( counter % 2 === 0) {  // "counter modulo 2"?  "0" means even number
        console.log("Mod case 0: Hello => fade and change to Hi  ");
        console.log("Request delayed changing to Hi");
        setTimeout(change2, 800);       // wait for 500 msfade to finish before you execute textbox change
    }

    console.log("Now request showing of changed textbox")
    setTimeout( showTextBox, 1000);     // wait for fade to finish before you execute textbox show
}

function hideTextBox () {
console.log("...fading out ...")
    $w("#textbox").hide("fade", { duration: 500 });
}

function showTextBox () {
console.log("...fading in ...")
    $w("#textbox").show("fade", { duration: 500 });
    console.log( "================================================     complete     =====================================");
console.log(" ");
}

function change1 () {
console.log("...changing to Hello ...")
    $w("#textbox").text = string2;
}

function change2 () {
console.log("...changing to Hi ...")
    $w("#textbox").text = string1;
}

I used the code for a text. I don’t want it to loop. Is there a way stop the looping? I want “hi” to go to hello and then stay on “hello”

https://russian-dima.wixsite.com/meinewebsite/test-1