简体   繁体   中英

Javascript event timing + 3rd party events, looking for a better alternative than setTimeOut()

I have the following HTML element stack:

<div class="btn-group btnSortAssType" data-toggle="buttons">
    <label class="btn ink-reaction btn-primary active">
        <input type="checkbox" value="m">Model
    </label>
    <label class="btn ink-reaction btn-primary active">
        <input type="checkbox" value="n">Assignment
    </label>
    <label class="btn ink-reaction btn-primary active">
        <input type="checkbox" value="p">Multi
    </label>
</div>

Since the button build above is not mutually exclusive, I am going over array + show/hide elements.

 $('.btnSortAssType').on('click', function (event) {
        let $allLables;
        var assTypeToShow = [];
        $(`.top-row`).hide();
        setTimeout(function () {
            $allLables = $('.btnSortAssType label.active');
            $allLables.each((index, label) =>{
                $(`.top-row[assignment_type="${$(label).find('input').val()}"]`).show();

            });
        })
    });

If you read the js abpve, you will see the element check going through setTimeout() , reason being: without it, it will miss the last click (so if 2 out of 3 are active, and clicking on the the last un-active element will still show 2 active).

I reckon this happens due to event timing between my code and bootstrap.js, where the method setting the element active somehow comes after my code, in my mind I assumed the event-loop didn't have that bootstrap active change in the event stack, so I used setTimeout() , I believe waits for the previous event stack to finish and runs after (null delay).

The results of having the above setTimeout() is 100% seamless, yet I want to know what I've missed here 'cause using setTimeout() seems like a cheap hack and I was wondering what you guys have in mind.

Many thanks for sharing, Bud.

The Bootstrap handler is attached to the document, and runs in the bubbling phase. So, event listeners attached to descendants of the document which also run in the bubbling phase will run before the Bootstrap handlers:

 $('.btnSortAssType').on('click', function(event) { console.log($('.active').length); });
 .active { color: blue; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.js"></script> <div class="btn-group btnSortAssType" data-toggle="buttons"> <label class="btn ink-reaction btn-primary active"> <input type="checkbox" value="m" checked>Model </label> <label class="btn ink-reaction btn-primary active"> <input type="checkbox" value="n" checked>Assignment </label> <label class="btn ink-reaction btn-primary active"> <input type="checkbox" value="p" checked>Multi </label> </div>

You can fix it by attaching your event handler to the document as well, and running your script after Bootstrap's (since listeners attached to the same element will run in the order they're attached):

 $(document).on('click', '.btnSortAssType', function(event) { console.log($('.active').length); });
 .active { color: blue; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.js"></script> <div class="btn-group btnSortAssType" data-toggle="buttons"> <label class="btn ink-reaction btn-primary active"> <input type="checkbox" value="m" checked>Model </label> <label class="btn ink-reaction btn-primary active"> <input type="checkbox" value="n" checked>Assignment </label> <label class="btn ink-reaction btn-primary active"> <input type="checkbox" value="p" checked>Multi </label> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM