Solution 1 :

.off() : The .off() method removes event handlers that were attached with .on()

You can it like :

$(document).off('click', '.vendorsListButton').on('click', '.vendorsListButton', function () { 
    //Your event logic here
    ...
}):  

It will detach the event first then attach a new one what will prevent duplication.

Better solution:
Since you’re using event delegation, you can attach the event just once and it will be working even for the newly added rows, so no need to recall _RenderVendorsList() every time.

So just remove the line _RenderVendorsList(); that is inside the other event, and call it one time at the start.

Maybe like:

var _RenderVendorView = function () {

    _RenderVendorsList();

    $(document).on('click', '#tableVendors tbody td:not(:first-child)', function () { 
    ...
       

Problem :

I have the below functions as a part of JS.

_RenderVendorView will trigger when clicking on a row of the table of vendors and it will show vendor details page,
And in vendor details view page there is a button with class .vendorsListButton, which will go back to table of vendors, means will trigger _RenderVendorsList

    var _RenderVendorsList = function () {

        $(document).on('click', '.vendorsListButton', function () {     
            jQuery.ajax({
                url: "/purchases/render_vendors_list",
                type: "POST",
                success:function(data){
                    $data = $(data); // the HTML content that controller has produced
                    $('#vendorcontainer').hide().html($data).fadeIn();
                    _TableVendors();
                    _RenderVendorForm();
                }
            });
        });
    };

    var _RenderVendorView = function () {

        $(document).on('click', '#tableVendors tbody td:not(:first-child)', function () { 
            if ($(this).index() == 4 ) { 
                // provide index of column in which we want prevent row click here is column of 4 index
                return;
            }
            else{
                var rowdata = $('#tableVendors').DataTable().row($(this).parents('tr') ).data();
                jQuery.ajax({
                    url: "/purchases/render_vendor_view",
                    type: "POST",
                    data: {vendor:rowdata.vendor_id},
                    success:function(data){
                        $data = $(data); // the HTML content that controller has produced
                        $('#vendorcontainer').hide().html($data).fadeIn();
                        _TableBills(rowdata);
                        _TableExpenses(rowdata);
                        _RenderVendorsList();
                    }
                });
            }
        });
    };

Now, problem is that 1st click on row open vendor page and 1st click on .vendorsListButton go back to vednors list,
2nd click on row also open vendor page, but when 2nd click on .vendorsListButton will run _RenderVendorsList two times, and on each iterate function run increase …

Not sure why it running multiple times on each forth and back.

What is wrong with this loop?

Comments

Comment posted by gaetanoM

This happens because you add more times an event handler…..

Comment posted by charlietfl

You are delegating event listeners to the document. That only needs to be done once. Unless you use

Comment posted by freedomn-m

If you’re using delegated event handlers (which you are) then you want to set them up once (even before the html has been built) and then do nothing. Don’t keep recalling

Comment posted by rjcode

How about this? actually i tried

Comment posted by Zakaria Acharki

It will work but it’s not an efficient solution, you’ll still call a function and render code that you don’t need, better to use

By