0

I have a JS code which is supposed to show sequentially messages sent class. There is class called Message Service. It implement the logic for showing a text message through class method showMessage(). It takes 2 seconds for message fading in and fading out. The logic assumes that if there is a new message sent while service for the previous message is not completed than it adds message to the queue. Then setTimeOut function checks if queue is not empty and if it is not it calls message service on first queue item.

The problem is that on first iteration of the service the code can’t get access to class variables this.service and this.messageStack and this.targetStack. It shows undefined. How can I get access to this.service and this.messageStack and this.targetStack variables in setTimeOut function, which recurcevely calls showMessage() method?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="show-message">Show message</button>
    <div id="holder">
    </div>
    <script>
        class MessageService {
            constructor() {
                this.service = 0;
                this.messageStack = []
                this.targetStack = []
                console.log('initiated')
            }


            showMessage(target, msg) {
                this.target = target
                this.msg = msg
                console.log(this.target + '  ' + this.msg)

                if (this.service === 0) {
                    console.log('here')
                    this.service = 1

                    let el = document.createElement('div')
                    el.setAttribute('id', 'thisMessage')
                    el.innerText = this.msg
                    let elStyle = document.createElement('style')
                    elStyle.innerHTML = ` #thisMessage {
                border: 1px solid purple;
                border-radius: 3px;
                width: 200px;
                height: 20px;
                display: flex;
                align-items: center;
                background-color: rgb(245, 202, 245);
                padding: 5px;
                padding-left: 10px;
                animation: fadeinout 2s linear forwards;
                -webkit-animation: fadeinout 2s linear forwards;
                opacity: 0;
                margin-top: 20px;
            }
            @keyframes fadeinout {
                50% {
                opacity: 1;
                }
            }
            @-webkit-keyframes fadeinout {
                0%, 
                100% {
                    opacity: 0;
                }
                50% {
                    opacity: 1;
                }
            }`
                    el.appendChild(elStyle)
                    document.getElementById(target).appendChild(el)

                    console.log(this.messageStack)

                    setTimeout(function () {
                        document.getElementById('thisMessage').remove();

                        this.service = 0

                        console.log(this.messageStack) // UNDEFINED ??????

                        if (this.messageStack.length >
                            0) { // CANNOT READ PROPERTIES OF UNDERFINED (READING "LENGTH") ?????
                            let newMessage = this.messageStack.pop()
                            let newTarget = this.targetStack.pop()
                            func.call.this.showMessage(newTarget, newMessage)
                        }
                    }, 2100)

                } else {
                    this.messageStack.push(this.msg)
                    this.targetStack.push(this.target)
                }
            }
        }

        let msg = new MessageService();
        msg.showMessage('holder', 'Print out all papers')
        msg.showMessage('holder', 'Update completed')
        msg.showMessage('holder', 'Server error')
    </script>

</body>
<style>

</style>

</html>

1 Answer 1

1

The problem is the this in the setTimeout refers to a different object. What you want to do is pass in a reference to the this you want.

I've done that below by creating a new variable that outside the setTimeout, and referred to that instead.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="show-message">Show message</button>
    <div id="holder">
    </div>
    <script>
        class MessageService {
            constructor() {
                this.service = 0;
                this.messageStack = []
                this.targetStack = []
                console.log('initiated')
            }


            showMessage(target, msg) {
                this.target = target
                this.msg = msg
                console.log(this.target + '  ' + this.msg)

                if (this.service === 0) {
                    console.log('here')
                    this.service = 1

                    let el = document.createElement('div')
                    el.setAttribute('id', 'thisMessage')
                    el.innerText = this.msg
                    let elStyle = document.createElement('style')
                    elStyle.innerHTML = ` #thisMessage {
                border: 1px solid purple;
                border-radius: 3px;
                width: 200px;
                height: 20px;
                display: flex;
                align-items: center;
                background-color: rgb(245, 202, 245);
                padding: 5px;
                padding-left: 10px;
                animation: fadeinout 2s linear forwards;
                -webkit-animation: fadeinout 2s linear forwards;
                opacity: 0;
                margin-top: 20px;
            }
            @keyframes fadeinout {
                50% {
                opacity: 1;
                }
            }
            @-webkit-keyframes fadeinout {
                0%, 
                100% {
                    opacity: 0;
                }
                50% {
                    opacity: 1;
                }
            }`
                    el.appendChild(elStyle)
                    document.getElementById(target).appendChild(el)

                    console.log(this.messageStack)
                    
                    let that = this;

                    setTimeout(function () {
                        document.getElementById('thisMessage').remove();

                        that.service = 0

                        console.log(that.messageStack) // UNDEFINED ??????

                        if (that.messageStack.length >
                            0) { // CANNOT READ PROPERTIES OF UNDERFINED (READING "LENGTH") ?????
                            let newMessage = that.messageStack.pop()
                            let newTarget = that.targetStack.pop()
                            //func.call.this.showMessage(newTarget, newMessage)
                        }
                    }, 2100)

                } else {
                    this.messageStack.push(this.msg)
                    this.targetStack.push(this.target)
                }
            }
        }

        let msg = new MessageService();
        msg.showMessage('holder', 'Print out all papers')
        msg.showMessage('holder', 'Update completed')
        msg.showMessage('holder', 'Server error')
    </script>

</body>
<style>

</style>

</html>

Sign up to request clarification or add additional context in comments.

1 Comment

Great! It works! Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.