Making sure your inline script is only included once when multiple content items are listed

Tags: development, JavaScript

It's a common scenario that you want to add a little piece of javascript to enrich your content part. You may find that putting it into a separate script file is an overkill or - because the script needs many parameters from the part's template - too complex. Thus, you go  with an inline script. Good choice! But did you know that if multiple content items having your part are displayed on the same page your script will be injected to the markup multiple times? That ain't good, but there's a simple workaround.

Code first!

    if (WorkContext.GetState<string>("OrchardHUN.Shoutbox.Includes") == null)
        using (Script.Foot())
            <script type="text/javascript">
                // This is only included once

        WorkContext.SetState<string>("OrchardHUN.Shoutbox.Includes", "set");

The sample is from our Shoutbox module in Parts.Common.Metadata.Summary-ShoutboxMessage.cshtml.

So what happens here? The WorkContext can contain a "state", i.e. key-value pairs that are only valid for the current request: if a value is set it can be read back later in the same request. We use this to have a value that indicates whether our script was already included or not (think include guards in C, yikes).

Having the same script included in Shoutbox's case would be harmless (it's just a variable declaration) but e.g showing an alert is a use case where you definitely want to prevent the script running more than once!

Happy not flooding the markup with repeated scripts!

No Comments

  • Bertrand Le Roy said Reply

    I'm not sure you should encourage people to be lazy ;) Script that is not initialization script (and those are instance-specific), should be put in a separate file, always.

  • Piedone said Reply

    Do you have anything about lazy people? :-) I agree with generally putting scripts to external files but this is really handy if your script is like 5 lines but needs 3 values from your model as input: this way it's just simpler to use an inline script.

Add a Comment