Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bootstrap select picker is not correctly removed / disposed during Template descruction #380

Open
jankapunkt opened this issue Jul 22, 2022 · 6 comments

Comments

@jankapunkt
Copy link
Collaborator

original finding by @lynchem

So I tried to dig into the issue we were having a little more. I believe the problem stems from a jquery control modifying the DOM. Our template is one we use for filters in a number of places. The reason we noticed the issue here is because on this particular page you can toggle from two sets of pre-defined values so it destroys and recreates the template. The template looks like this

<template name="multipleSelectFilter">
    <select id="{{queryParamKey}}-select" class="form-control selectpicker show-tick" multiple="multiple"
        data-actions-box="true" data-selected-text-format="count > 3">
        {{#each options}}
            <option value={{value}}>{{label}}</option>
        {{/each}}
    </select>
</template>

In our onRendered we do $(this.jquerySelector).selectpicker(); to initialise the control. So in the DOM instead of just our select I now have.

<div> //new parent added by the control
    <select></select> //our initial select 
    <button></button> //added by the control
</div>

In our onDestroyed we call $(this.jquerySelector).selectpicker("destroy"); but it doesn't clean up any of the new elements it created and leaves the button & enclosing div. I removed the onDestroyed callback entirely incase it was somehow preventing the default destruction from happening and it also only destroys the initial select that was part of our template. So every time I switch views on this page I end up with the old <div><button></button></div> lying around.

Has something changed with how we track what we need to remove? I'm not sure if the previous behaviour was simply to nuke everything and now we're trying to track what we should delete?

@jankapunkt jankapunkt added this to the Blaze 2.6.2 milestone Jul 22, 2022
@ziedmahdi
Copy link

We had the same issue. We have noticed that blaze does not destroy first level added element. As a workaround, we have embedded the select tag inside a div tag.

<template name="selectPicker">    
    <div>
        <select id="{{htmlId}}" name="{{name}}" class="border-1 border-light rounded-2 form-control" {{otherAttributes}}>
            {{#each options}}
                <option value="{{value}}" class="{{../optionClass}}" selected="{{selected ../value value}}" data-icon="{{colorClass}}">{{title}}</option>
            {{/each}}
        </select>
    </div>
</template>

We always add a wrapping tag that must not be modified by any external library.

<template name="Icon">
    <span>
        <i class="{{class}}" style="{{style}}" {{otherAttributes}}></i>
    </span>
</template>

@jankapunkt
Copy link
Collaborator Author

@ziedmahdi thank you for clarifying, I actually thought all the time the <span> around the icons were necessary due to some issues with SVG or Icon fonts or something, but now this makes total sense, thanks a lot for further investigation and pointing to the right direction.

@jankapunkt
Copy link
Collaborator Author

jankapunkt commented Oct 18, 2022

This bug is reproducible in the following way:

use jquery or vanilla DOM manipulation and replace the root component of the template with any custom code but don't use any Blaze functionality, such as reactive vars, tracker or Blaze API.

For example:

<template name="test"><div class="test-root">hello</div></template>

Add this to any parent template with a conditional, such as :

{{#if condition}}{{> test}}{{/if}}

Now manipulate the template's DOM via jquery in an event that is triggered in the parent template:

const target = $('.test-root')
const parent = target.parent()
// at this point starts the problem, where
// the DOMRange can't catch up anymore:
target.remove()
parent.append('fooooo')

The template will now display fooooo instead of hello but it's not within the test template's DOMRange anymore. When DOMRange._destroy is called on the current Template's view it will not catch up these nodes and therefore not remove them.

@StorytellerCZ StorytellerCZ modified the milestones: Blaze 2.6.2, Blaze 3.0 Nov 17, 2022
@StorytellerCZ
Copy link
Collaborator

Related to #353

@salmanhasni
Copy link

we had the smiliar issue with select2, jquery select2 append its html part in else of DOM

Template.dynamicTableTableCell.helpers({
  editing() {
    return Template.instance().editing.get();
  }
});
<template name="dynamicTableTableCell">
  {{#unless editing}}
    <span class="dynamic-table-cell-wrapper">
      {{> Template.dynamic template=templateName data=templateData}}
      {{#if editable}}
        <span class="dynamic-table-enable-editing"><i class="fa fa-pencil"></i></span>
      {{/if}}
    </span>
  {{else}}
      {{> Template.dynamic template=editTemplateName data=editTemplateData}}
  {{/unless}}
</template>

when edditing is false after the true we endup having a two template one which is generated for dynamic-table-cell-wrapper and another which is create by select2 in else part of condition, right now the work arround we have is to wrap the else part with div with specific class, for example

  {{else}}
    <div class="editing">
      {{> Template.dynamic template=editTemplateName data=editTemplateData}}
    </div>
  {{/unless}}

we had this before working, but recently updating the meteor cause us this issue.

@jankapunkt
Copy link
Collaborator Author

jankapunkt commented Dec 5, 2023

@salmanhasni

we had this before working, but recently updating the meteor cause us this issue.

Can you restore the Meteor and Blaze versions where this was working?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants