2

What is the best way of adding external files from a partial view?

I need to do something like this

code in partial view:

@{
    var files = new List<string>();
    files.Add("some path");
    files.Add("some path");
    ViewBag.Files = files;
}

in layout page

@foreach (var file in ViewBag.Files) {
    @file
}

this does not actually work though

3
  • what will be the content of external files? css? js? wouldn't you be better with a simple client.css and one client.js where you can dynamically add whatever? - Let me know what kind of files and I will show you what I doing on my end. Commented Oct 6, 2011 at 15:14
  • @balexandre I'm creating a simple cms where the developers should be able to create plugins as partial views (editor templates). The plugins can contain css och js for that specific plugin. Are you with me? Commented Oct 6, 2011 at 15:34
  • @balexandre can you show me how your solution works? Commented Oct 8, 2011 at 23:10

3 Answers 3

6

As promised

You can't render @section's as it's not supported when rendered by Partial Views, until then you can do this trick:

in your _Layout.cshtml write

@RenderSection("scripts", false)
@Html.RenderSection("scripts")

The first one is the default, the second line is your brand new way to render a section, I use both in my code...

Now let's add some code to our Partial View

instead of

@section scripts { 
   <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
   <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
}

replace it with:

@Html.Section(
    @<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>, "scripts"
)
@Html.Section(
    @<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>, "scripts"
)

and our little helper that you just put inside your Models folder and reference it in your Partial View and Layout Page

// using idea from http://stackoverflow.com/questions/5433531/using-sections-in-editor-display-templates/5433722#5433722
public static class HtmlExtensions
{
    public static MvcHtmlString Section(this HtmlHelper htmlHelper, Func<object, HelperResult> template, string addToSection)
   {
      htmlHelper.ViewContext.HttpContext.Items[String.Concat("_", addToSection, "_", Guid.NewGuid())] = template;
      return MvcHtmlString.Empty;
   }

   public static IHtmlString RenderSection(this HtmlHelper htmlHelper, string sectionName)
   {
      foreach (object key in htmlHelper.ViewContext.HttpContext.Items.Keys)
      {
         if (key.ToString().StartsWith(String.Concat("_", sectionName, "_")))
         {
            var template = htmlHelper.ViewContext.HttpContext.Items[key] as Func<object, HelperResult>;
            if (template != null)
            {
               htmlHelper.ViewContext.Writer.Write(template(null));
            }
         }
      }
      return MvcHtmlString.Empty;
   }
}

To render CSS, all you need to so is using other section name, for example:

In _Layout.cshtml

@Html.RenderSection("styles")

in your Partial Views

@Html.Section(
  @<link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.3.0/bootstrap.min.css">, "styles"
)

I hope this helps.

Sign up to request clarification or add additional context in comments.

2 Comments

this solution seems to work pretty good, I guess I need to put @Html.RenderSection("styles") before </body> to get this to work properly because the partial view needs to be before the RenderSection.
Hi there, I have a late question regarding this solution. It seems like the sections i rendered in a random order? e.g. adding multiple scripts will cause some problems for me.
1

Instead of holding values in Viewbag try to hold values in HttpContext.Current.Items which is request scope.

Like this HttpContext.Current.Items.Add("files", files)

2 Comments

I would never use that as you can easily loose the context when dealing with several scenarios, for heavy stuff you should use TempData, but for holding a list of strings ... ViewBag or ViewData is more than enough!
You can not access saved values in Layout if you use ViewBag or ViewData. TempData works till next request and it would cause wrong results. I wonder what kind of scenarios causing to lose context ? I actualy used this in my own application and worked well.
0

Maybe you can use sections for that. In your layout:

<head>
...
    @RenderSection("Head", false)
</head>

The false parameter indicates the section isn't required.

In your partial view you do something like this:

@section Head
{
    foreach(file in Model.Files}
    {
        .... render css/js links here
    }
}

This works for views, not entirely sure it works with partialviews, but it should :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.