Marko: Strange bug with component tagName

Created on 11 Jul 2017  路  5Comments  路  Source: marko-js/marko

I have two component

            <div class="input__wrapper">
                <multi-select onChange("setLanguages") name="language" multiple options=state.languageOptions value=state.languages></multi-select>
            </div>

multi-select.marko

<div class="multi-select">
    <div class="multi-select__items">
        <div class={'multi-select__item': true, 'multi-select__item_active': component.isActive(value)} for(value, option in input.options) onClick("selectItem", value)>
            ${option}
        </div>
    </div>
</div>

Before data was changed, component renders into next code with H3 tags

<h3 class="multi-select" id="b1-_r0-c0-0[0]"><div class="multi-select__items"><div class="multi-select__item multi-select__item_active">All</div></div></h3>

After data changing

<div class="input__wrapper"><div class="multi-select" id="b1-_r0-c0-0[0]"><div class="multi-select__items"><div class="multi-select__item multi-select__item_active">All</div></div>
bug

Most helpful comment

@westtrade In the latest beta version (npm i marko@beta) we have some changes to the way templates are compiled and diffed that should solve this. If for some reason that is not the case, let us know and we'll reopen this issue.

All 5 comments

This bug can be reproduced in template with include and if tags combination . In some cases (when template data in child components don't changed) morphdom, when tagName was changed, don't recreate element, and previous tagName remains unchanged. I try to create more clear test case

I made an example of a code which reproduce this bug.

layout.marko

class {
    onCreate(input) {
        this.state = {
            page: '1',
        }
    }

    switchPage(currentPage) {
        this.setStateDirty('page', currentPage);
    }
}

<button onClick("switchPage", '1')>Page 1 ${ state.page === '1' ? 'active' : ''}</button>
<button onClick("switchPage", '2')>Page 2 ${ state.page === '2' ? 'active' : ''}</button>

<div>
    <c1 if(state.page === '1')><@title>Page 1 TITLE</@title></c1>
    <if (state.page === '2')>
        <c2><@header>Page 2 TITLE</@header></c2>
    </if>
</div>

c1.marko

class {
}

<div>
    <h1 if(input.title)>
        <include(input.title)/>
    </h1>
</div>

c2.marko

class {
}

<header if(input.header)>
    <div class="container">
        <include(input.header) />
    </div>
</header>

When page state changed to '2', tagName h1 in visible component still preserved. I made short video with example

https://media.giphy.com/media/xTkcEwgtAzx1xYBTEY/giphy.gif

If tagName for header tag switch to div tag, all worked normally. Also it worked correctly, if i remove class in c1 or c2 component, or in both components at once.

@westtrade In the latest beta version (npm i marko@beta) we have some changes to the way templates are compiled and diffed that should solve this. If for some reason that is not the case, let us know and we'll reopen this issue.

In version 4.5.0 I have many bugs (with event listeners, with redrawing all DOM tree - when changed state in deep child component) and one infinite loop which appeared after redrawing components.

A little later I will try to describe the bugs found in more detail

div.dropdown [
        class=component.class
        role=input.role
        onMouseenter("reactOnHover", true)
        onMouseleave("reactOnHover", false)
    ]

This code in nested components will reproduce next error

Cannot read property 'addEventListener' of undefined
    at addEventListenerHelper (init-components-browser.js?d148:69)
    at addDOMEventListeners (init-components-browser.js?d148:76)
    at init-components-browser.js?d148:123
    at Array.forEach (<anonymous>)
    at initComponent (init-components-browser.js?d148:115)
    at Function.initClientRendered [as ___initClientRendered] (init-components-browser.js?d148:155)
    at ComponentsContext.___initComponents (ComponentsContext.js?d16e:36)
    at RenderResult.afterInsert (RenderResult.js?75f6:46)
    at Component.js?851e:483
    at Object.batchUpdate [as ___batchUpdate] (update-manager.js?28fc:63)

Current bug was fixed.

Was this page helpful?
0 / 5 - 0 ratings