Ezekiel NKstars
Ezekiel NKstars

Reputation: 13

JavaScript TypeError: can't access property "offsetLeft", this is undefined

I've been stuck for a few days. I can't fix my error, I tried adding .bind (this) but it doesn't work. Do you have any idea

errors : TypeError: can't access property "style", this.menu_indicator is undefined I will have an error on this line this.menu_indicator.style.left = this.menu_position + "px";

here is my code js , html , css

class TabBar {
    constructor()
    {
        this.menu_bar = document.querySelector('.tab-bottom-bar');
        this.menu_item = document.querySelector('.tab-menu-item');
        this.menu_indicator = document.querySelector('.tab-nav-indicator');
        this.current_item = document.querySelector('.tab-current');
        this.menu_position;
    }

    initMenu()
    {
        this.menu_position = this.current_item.offsetLeft -16;
        this.menu_indicator.style.left = this.menu_position + 'px;
        this.menu_bar.style.backgroundPosition = this.menu_position -8 + 'px';
        let parent = this.menu_item.parentElement;
        Array.prototype.forEach.call(parent.children,
            function(select_menu_item){
                select_menu_item.addEventListener('click', function(e){
                    e.preventDefault();
                    this.menu_position = this.offsetLeft - 16;
                    this.menu_indicator.style.left = this.menu_position + 'px;
                    this.menu_bar.style.backgroundPosition = this.menu_position -8 + 'px';
                    [...select_menu_item.parentElement.children].forEach(
                        sibling => {
                            sibling.classList.remove('tab-current');
                        });
                    select_menu_item.classList.add('tab-current');
                }.bind(this));
            }
        )
    }
}

let menu_tab = new TabBar();
menu_tab.initMenu();
:root{
    --primary-color:#0D6FFA;
    --accent-color:#49CE95;
    --danger-color:#EC3582;
    --fore-color:rgba(0,0,0,0.65);
    --main-cast-shadow: 0px 3px 12px rgba(0, 0, 0, 0.08), 0px 3px 6px rgba(0, 0, 0, 0.12);
}
body{
    background-color:#D9D8D7;
}
.tab-bottom-bar{
    position:absolute;
    display:flex;

    padding: 16px 36px;
    justify-content:space-between;
    width:335px;
    margin:auto;
    top:0;
    left:0;
    bottom:0;
    right:0;
    height: 32px;

    font-size:26px;
    background-image:radial-gradient(circle at 36px 6px,transparent 36px, #ffffff 37px);
    filter: drop-shadow(0px -1px 6px  rgba(0, 0, 0, 0.08)) drop-shadow(0px -2px 12px  rgba(0, 0, 0, 0.12));
    border-bottom-left-radius:30px;
    border-bottom-right-radius:30px;
    transition: cubic-bezier(0.57, 0.23, 0.08, 0.96) .45s;
}

.tab-nav-indicator{
    position:absolute;

    width: 56px;
    height: 56px;
    bottom: 28px;
    margin: auto;
    left: 0;

    background-color: #000000;
    box-shadow: var(--main-cast-shadow);
    border-radius:50%;
    transition: cubic-bezier(0.45, 0.73, 0, 0.59) .3s;
}
.tab-menu-item{
    color:var(--fore-color);
    transition:ease-in-out .5s;

    cursor: pointer;
}
.tab-current{
    position:relative;

    color:#ffffff;

    z-index:3;
    transform:translate3d(-2px,-22px,0px);
}
<div class="tab-bottom-bar">
            <a href="#" class="tab-menu-item tab-current"><i class="fas fa-home"></i></a>
            <a class="tab-nav-indicator"></a>
            <a href="#" class="tab-menu-item"><i class="fas fa-book-reader"></i></a>
            <a href="#" class="tab-menu-item"><i class="fas fa-user-tie"></i></a>
            <a href="#" class="tab-menu-item"><i class="fas fa-at"></i></a>
</div>

Upvotes: 0

Views: 719

Answers (2)

Ezekiel NKstars
Ezekiel NKstars

Reputation: 13

it looks like it loses offsetLeft of the indicator shot does not move, I can't fix it.

Error fixed :)

class TabBar {
constructor()
{
    this.menu_bar = document.querySelector('.tab-bottom-bar');
    this.menu_item = document.querySelectorAll('.tab-menu-item');
    this.menu_indicator = document.querySelector('.tab-nav-indicator');
    this.menu_current_item = document.querySelector('.tab-current');
    this.menu_position;
}

initMenu()
{
    this.menu_position = this.menu_current_item.offsetLeft -16;
    this.menu_indicator.style.left = this.menu_position + "px";
    this.menu_bar.style.backgroundPosition = this.menu_position - 8 + 'px';
    let that = this;
    this.menu_item.forEach(function(select_menu_item) {
        select_menu_item.addEventListener('click', function (e) {
            e.preventDefault();
            that.menu_position = this.offsetLeft -16;
            that.menu_indicator.style.left = that.menu_position + "px";
            that.menu_bar.style.backgroundPosition = that.menu_position - 8 + 'px';
            [...select_menu_item.parentElement.children].forEach(
                sibling => {
                    sibling.classList.remove('tab-current');
                });
            select_menu_item.classList.add('tab-current');
        });
    })
}

}

let menu_tab = new TabBar(); menu_tab.initMenu();

Upvotes: 0

Eldar
Eldar

Reputation: 10790

This is called this problem. When you nest functions as you do, you created nested scopes. In those scopes, this reference changes as the nesting goes. If you want to keep the reference you have 2 choices.

  1. Use arrow functions
  2. Define a variable that points the right this
 // this  is different
Array.prototype.forEach.call(parent.children,
      function(select_menu_item){
       // than this
         select_menu_item.addEventListener('click', function(e){
              // and this is different than the other two

Solution 1

 Array.prototype.forEach.call(parent.children,
            (select_menu_item) => {
                select_menu_item.addEventListener('click', e=> {

Solution 2

let that= this;
Array.prototype.forEach.call(parent.children,
      function(select_menu_item){
        select_menu_item.addEventListener('click', function(e){
                      // use that here.

Upvotes: 3

Related Questions