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

Intercooler.ready is executed on document.ready #320

Closed
trailmax opened this issue May 22, 2020 · 9 comments
Closed

Intercooler.ready is executed on document.ready #320

trailmax opened this issue May 22, 2020 · 9 comments

Comments

@trailmax
Copy link

From documentation I understand that Intercooler.ready should be called on completion of successful DOM load.
However I see that this is also executed on page load, without any AJAX calls whatsoever. This is causing issues with element bindings and is totally unexpected.

See this reproduction:

<html>
<head>
	<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/intercooler-js/1.2.3/intercooler.js"></script>

	<script>
		Intercooler.ready(function (rootContent) {
			console.log("Intercooler.Ready");
		});
	</script>
</head>
<body>
</body>
</html>

On page load in console you'll see the log output.

Is this an intended behaviour?

@adamstep
Copy link
Collaborator

I believe it is intended, the initial page load is also a DOM load so it makes sense. Any bindings that need to happen after Intercooler swaps content should also happen when the page first loads.

Can you post a specific example where your having issues? I may be able to help.

@trailmax
Copy link
Author

@adamstep I was under impression for Inetrcooler.ready to trigger DOM needs to load through Intercooler, not any other way.
So does it mean that DOM loaded through other means will also trigger Intercooler.ready? I'm talking about something like this:

        let request = $.get("~/myEndpoint");
        request.done(function (html: string) {
            $('#reloadme').append(html);
        });

As for concrete proglem, it is element double binding. We have a function that binds all the elements that needs binding, something like BindAllElements(selector) where it goes through selector and does the bindings. On document.ready we call BindAllEmenents('body').
And then every time we reload parts of pages we call BindAllElements('#reloadme').

Now we are trying out Intercooler on small part of our application and do this:

Intercooler.ready(function (rootContent) {
            BindAllElements(rootContent.selector)
    });

When the page is loaded it effectively calls BindAllElements('body') for the second time, after we already done that first binding. Thus causing double bindings on elements.

For now I've worked around like this:

Intercooler.ready(function (rootContent: any) {
        if (rootContent[0].tagName !== "BODY") {
            BindAllElements(rootContent.selector)
        }
    });

But this feels very hacky, hence my question here.

@jsampson
Copy link
Collaborator

I think this is a case of the docs not matching the intent. The reference page does indeed say " to be run on the top level of all content that is swapped into the DOM by intercooler." However, I've always thought of it as simply meaning "when Intercooler is ready," i.e. Intercooler has processed all the elements on the page (either when first loaded or when swapped in). In your example, I would simply get rid of the document.ready and eliminate the if inside Intercooler.ready.

Can we consider this a documentation bug and fix the wording rather than changing the behavior (which other Intercooler apps already depend on)?

@1cg
Copy link
Contributor

1cg commented May 23, 2020

Yeah, this isn't documented that well and needs a fix.

Basically Intercooler.ready is the intercooler replacement for $.ready, except you have to do all initialization within the elt passed in, rather than globally as you would with $.ready.

@1cg
Copy link
Contributor

1cg commented May 23, 2020

I wanted to have one place where you did your initialization code for both the initial body load as well as any AJAX calls.

@baumann74
Copy link
Contributor

baumann74 commented May 23, 2020 via email

@trailmax
Copy link
Author

Hello Anders,

By element bindings I mean our elements, not Intercooler's. We use KendoUI for datepickers, colourpickers, etc. We need to tell Kendo what should be a datepicker, what should be a colour picker, etc. So we have loads of bits of code that do:

       $selector.find('input.datep').kendoDatePicker({
            format: "dd/MM/yyyy"
        });
        $selector.find('input.datetimep').kendoDateTimePicker({
            format: "dd/MM/yyyy HH:mm"
        });
        $selector.find('input.colorPicker').kendoColorPicker();
        // etc.

When new bits of DOM are loaded we need to execute those binders on the new elemenets, otherwise Kendo does not pick it up. As far as I can see Intercooler.processNodes only deals with Intercooler bindings, nothing external. Hence the usage of Intercooler.ready.

As for replacing $.ready with Intercooler.ready - we can't do that, as we have hundreds of pages where sometimes we are binding page-specific elements retest or rewrite all those pages is not an option.

So if you are saying this is an intended behaviour, we'll just keep what we have with the test for BODY. Unless there is a better way you can suggest.

Thanks for looking into this!

@baumann74
Copy link
Contributor

baumann74 commented May 25, 2020 via email

@trailmax
Copy link
Author

@baumann74
I see, I'll give this a try, but I sense repeating the binding code on every partial page smells of DRY violation.

Thank you for your time and help on this, very much appreciated!

Cheers,
Max

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

No branches or pull requests

5 participants