3

The site that I am working on has a list of CSS files. The CSS files are added to the list within a component’s view, then the main layout’s view will add all of the CSS files within this list to the header of the page.

When a user adds a new component to the page through Experience Editor, the CSS file is added to an iframe with an ID of scLoadingFrame. This causes the component not to have the styles applied to it. When the page is saved, and it reloads, then the CSS file is put into the header of the webpage, and the component has the styles applied to it.

Is there a way to get the main layout’s view to put the CSS references outside of the iframe when adding a component through Experience Editor?

  • To clarify you want to see the style change in Experience Editor when they add the iframe? Do you reload the page in Experience Editor? – RReilley Feb 28 '17 at 14:11
  • I think that the iframe comes from Sitecore. When my main layout gets call after adding a component, the CSS is inserted into: <iframe id="scLoadingFrame" height="0px" width="0px" src="url">. My component is not located in this iframe. – user1619 Feb 28 '17 at 16:10
  • I think my issue is, that the page is not getting refreshed when a component is added to the page. – user1619 Feb 28 '17 at 19:06
  • I think that is normal Sitecore before. In the past I had to save first. There might be a way to overwrite the pipeline and refresh without saving. – RReilley Feb 28 '17 at 20:56
2

The implementation that you are describing is meant to add similar support to Sitecore as the .NET MVC RenderSection functionality that Sitecore MVC does not natively support.

Basically, what you need to do is take the <link> (I am assuming that you have the <link> node in your <iframe> but this solution will work for <style> nodes or just the CSS file URL too, with very minor tweaks) element that was added to the <iframe id="scLoadingFrame"> and move it to the <head> of the actual page. However, bear in mind the following:

  1. Should only run when in the Experience Editor
  2. Should only run when a new component that has an associated CSS file is added to the page and should only run for that component

With that in mind, you can implement what you are looking for by doing the following:

First, create a partial view, _ExperienceEditorDynamicCssLoader, that you statically pull into the bottom of your Layout's view via the following:

if (Sitecore.Context.PageMode.IsExperienceEditor)
{
    @Html.Partial("~/path/to/_ExperienceEditorDynamicCssLoader.chstml");
}

Second, in your new _ExperienceEditorDynamicCssLoader partial view, write a delegated JavaScript event handler (you don't have to use jQuery, but their docs do a good job of explaining event delegation) to your page that will listen for components being added or <link> elements being added to an <iframe>. I haven't tried this with the Experience Editor, so you may need to experiment a bit in order to find the best place to assign this handler and the best event to listen for, but know that events should propagate up the <iframe>. Note that you need a delegated JS event handler because a delegated handler listens for events that occurred on child/descendant elements, rather than listening for an event from a specific element or set of elements. This means that a delegated handler can actually listen for elements that are't on the page when the handler was attached.

Third, write the body of your delegated event handler such that it takes the <link> element from the <iframe> and moves it to the <head> of the current page. The following are a few examples of what this might look like in jQuery (which, again, is optional).

If the actual <link> node is what gets added to the <iframe> then the body of your handler should be pretty simple and similar to following:

$(this).find("link").appendTo("head")

Alternatively, if you only have the URL of the CSS and not the actual <link> element in the <iframe> then you may need to writing something similar to the following:

// get the elements with the URLs from the iFrame
$(this).find("selector for elements containing the CSS file URLs")
    // move the link from each to the head of the page
    .each(function() { 
        var cssFileUrl = $(this).GetCssFileUrl(); // replace this call with your own
        $('<link rel="stylesheet" type="text/css" href="' + cssFileUrl + '" >')
            .appendTo("head");
    });

This will actually construct the <link> node for you to append to the <head>.

Once you have that, you should be good to go. Your rendering should only ever render in the Experience Editor and all it should do is add the delegated handler, listen for <link> elements being added to the page and then move those elements to <head> of the page you are currently editing. The styles should apply as soon as the <link> element is added to the <head>.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.