skip to Main Content

I’ve been down trying to find this bug but I can’t. Everything works well in my code except for the function "typewriter" that refuses to be !undefined.

var xtrans = document.getElementById("xtext");
var xshowed = document.getElementById("xcontain");

function xsend() {
  var gotten = xtrans.value;
  if (/^s*$/.test(gotten) == true) { // the crazy  /^s*$/.test(gotten) there is to check for a whitespace only on a condition that no text has been added. its a returns a boolean value, "true or false,"" so i set it to true, and if it happens, the code of block is executed.
    return false; //all actions if the condition is true will be aborted
  }
  else {
    xshow(gotten);
    xtrans.value = ""; //this is to clear the text after clicking send
  }
}

function xshow(gotten) { //gooten was put here so it could pass its value below since its value was originally gotten in another function which will not work elsewhere like a global stuff.
  const ximagine = document.createElement("div"); //to create an element so the text from gotten can be placed in it as its content.
  ximagine.textContent = gotten; //to get the text that gotten carries and place it into the element created.

  if (ximagine.textContent) { //this is to make sure a text which is null or u defined will not go past this block of code. ( like a  filter).
    var xfinal = xshowed.appendChild(ximagine); //the container xshowed where the x imagine was appended to had a blue border so i could see where the text entered. all the text entered the border but i wanted them to look somewhat seperate, hence i cleared all design from the container to make it look blank and i made designs to the incoming texts so they would look like they were sent differently.
    xfinal.classList.add("ended"); //this is to add whatever design i want.
    xbot(gotten) //call this function if everything is successful
  }
  else {
    document.write("fatal error, please refresh this page and don't put such text anymore, else you will be suspended for 6 months");
  }
}

function xbot(gotten) {
  //  gotten.trim(); //to remove whitespace both from front and back of the string.
  if (gotten == "Hi" || gotten == "Hello" || gotten == "Robot?" || gotten == "Anyone?") {
    console.log("validated");
    const xpro = document.createElement("div");
    var xreturn = xshowed.appendChild(xpro);
    xreturn.classList.add("xended");
    xblinker = document.createElement("p");
    xblinker.id = "blink";
    var xreply = document.createElement("p");
    xreply.id = "typed";
    xpro.appendChild(xblinker);
    xpro.after(xreply); //to add the  xreply element and xblinker element to the parent element xpro when they're formed
    var xreplyy = document.getElementById("typed");
    var blinky = document.getElementById("blink"); //this is to get the element that will be blinking in front of text.

    blinky.style.display = "inline";
    blinky.style.borderRight = "10px solid white";

    // set up text to print, each item in array is new line
    var aText = new Array(
      "There are only 2 types of people in the world:",
      "The ones who have dominated in increasing their capacity to think, and the ones who wallow in ignorance"); //the two text strings, but here they're like objects because of the "new" keyword.
    var iSpeed = 100; // time delay in typing out each character 
    var iIndex = 0; // start typing the array text at this position, thats at beginning.
    var iArrLength = aText[0].length; // the length of the first string, thats the one before the comma of the text array.
    var iScrollAt = 20; // point at which text start scrolling up, start scrolling up at this many lines. its not really important.
    var iTextPos = 0; // the text position after displaying a character.
    var sContents = ""; // initialise contents variable
    var iRow; // Not so important, This variable is used to keep track of which lines of text have already been typed out and should be displayed on the web page.

    typewriter(); //calls the function to trigger the code below 

    function typewriter() {
      sContents = ""; //repeated though
      iRow = Math.max(0, iIndex - iScrollAt); //rhis only tries to see which is the largest number. if you solve iindex-iscrollat, you'd get -20. between -20 and zero, zero is bigger, so math.max picks it and it is now assigned to iRow. you can console.log iRow to check its value. i think it is better to just say iRow is equal to zero, instead of passing through the stress.
      var destination = document.getElementById("typed"); //get the element that it the array text would be appended to.

      while (iRow < iIndex) { //the while here is a type of loop, while the iRow is less than the position of the text in the array. execute the below code as long as the condition is true. this condition is only true when the iIndex has been moved to 1 or the next string. that means this code for the next text string after the first. tested with console.log(iRow, iIndex);
        sContents += aText[iRow] + "<br>"; //mind you, increment of zero is 1.
        iRow++;
      }

      destination.innerHTML = sContents + aText[iIndex].substring(0, iTextPos) + blinky.innerHTML; //this code will run first for the first string text ie iIndex equal to 0. then it will run a second time, but this time it will add the next steing text to the first one, which will make them stay in the same element called destination it was tested with this "console.log(sContents);" 

      //the substring starts from 0, thats first character and returns the following characters as iTextPos increments. one by one.
      if (iTextPos++ == iArrLength) { //the heart of the code. this says if the increment in the textposition is equal to the length of the text in that particular string. it won't work if iTextpos++ is put as iTextpos, because it is always incrementing. check this out to see "console.log(iTextPos);"
        iTextPos = 0; //text position is reseted here.blinky.style.borderRight = "10px solid white"; //to show itself
        blinky.style.display = "inline"; //very important, to make it inline with the text which i alredy made display as inline too, in order for them to appear on same line together.
        iIndex++; //iIndex is incremented, and thats what causes iIndex to turn to 1 meaning next line, if theres another, it will turn to 2 and so on.
        if (iIndex != aText.length) { //it will almost likely never be equal to it, so the below code will always run.
          iArrLength = aText[iIndex].length; //the iArrLength is updated with new length for new string or next string.
          setTimeout("typewriter()", 500); //function is then called again after 500ms, so as to render the next text out.
        }
      }
      else {
        setTimeout("typewriter()", iSpeed); //if no new line, call function after iSpeed value
      }
    }
  }
}

I’m trying to make a kind of bot that responds to already fixed text input with the text i filled it with.

I’m trying to replicate my own chatgpt frontend. So it has some chatgpt like effect on text.

That’s the whole source. The code is a little bit complicated.

The blink effect of the blinker will be taken care of with css. I opted for this because if I used css alone to do the text effect, I would only be able to do a max of a line of text because it uses 100% width of the text to display it, unlike js.

The problem: thetypewriter() doesn’t call the function typewriter() . It just end up being undefined in console. I don’t think I have any typo in the code (not the comments though).

What I’m I gonna do to call that function, because without it the text stored to be typed out can’t be typed out. So I have a cursor blinking in the container that it was appended to.

Sorry the code is a little bit messy, I’m just going crazy.

I tried using "use strict" because I read from somewhere on stack overflow, that a function running under an if statement doesn’t go well, and I tried using setIntervalto run the code with the thought that maybe the where the typewriter() call was was not okay. Then I clear it out by putting clearInterval first inside the to be called function. I expected it to work.

2

Answers


  1. Instead of passing the function as a string to setTimeout (like you do with setTimeout("typewriter()", 500);), you need to pass the function itself like this: setTimeout(typewriter, 500);. Same goes for the other setTimeout: setTimeout(typewriter, iSpeed);.

    Why can’t you use a string here? Because, as mentioned in the comments, using a string instead of passing a function will run the string in the global scope, and since typewriter is defined inside of another function, it will be inaccessible from the global scope.

    Login or Signup to reply.
  2. I’m not super well versed in closures, but I think that your code is failing due to setTimeout creating a closure when it gets called initially (before the timeout occurs). This makes a context where your function doesn’t exist yet (I think). You can get around this by using the other syntax of setTimeout, where you give it a callback function without invoking it. So instead of

    setTimeout("typewriter()", 500);
    

    try

    setTimeout(typewriter, 500);
    
    

    Below I threw together two functions, one using your current syntax and one with my suggested syntax

    myFunc(10)
    
    // works
    function myFunc(num) {
      if (num > 0) {
        console.log(num)
        setTimeout(() => myFunc(num - 1), 500)
      }
    }
    
    myOtherFunc(10)
    
    // doesn't work
    function myOtherFunc(num) {
      if (num > 0) {
        console.log(num)
        setTimeout('myOtherFunc(num - 1)', 500)
      }
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search