Can I apply Dart's string interpolation dynamically? - dart

(from the Dart discussion mailing list by Tristan McNab)
I'm trying to build a server-side MVC framework and generating views based on templates and whatnot, and I was wondering if I could apply Dart's string interpolation dynamically. For example, this would be my view template:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${ViewData["Title"]}</title>
<link href="/Content/css/site.css" rel="stylesheet" />
</head>
<body>
<h1>${ViewData["Title"]}</h1>
<div id="container">
<p>Hello world!</p>
</div>
</body>
</html>
And I'd like to apply the ViewData variable using:
static String applyViewData(String html, Map ViewData) {
// apply interpolation here
}
Is this at all possible at the moment? My searching for the APIs indicates that it isn't.

(posted by Bill Hesse)
By wrapping the string literal in a function that takes the context as
a parameter, you can have a Function : context -> String that you can
pass around instead of a String. If you need to use some String
operations, like concat, on these objects, you can implement these
operations on a class encapsulating this type ("lifting" them). This
seems like a straightforward way to give the string literal in one
place, and give the data you want to interpolate in another.
String interpolation always happens dynamically, each time the literal
is used, and the data can easily come from a parameter to a function
rather than from the lexical context.
For example:
Function MyTemplate() {
return (Context context) {
return "<table><tr><td class=${context.leftColumnClass}>Red Sox</td><td>${context.data}</td></tr></table>";
}
}
...
var templateHere = MyTemplate();
...
var output = templateHere(context);
You could also skip a level of indirection and just create
String FillMyTemplate(Context context) => '''
<html><head><title>$context.title</title></head>
''';
and use FillMyTemplate where you need the template.

(posted by Sam McCall)
There's a trick involving noSuchMethod():
class Template {
var _context;
noSuchMethod(method, args) {
if (!method.startsWith("get:")) return super.noSuchMethod(method, args);
return _context[method.substring(4)];
}
abstract String template();
String evaluate(context) {
_context = context;
try {
return template();
} finally { _context = null; }
}
}
And then create a subclass:
class MyTemplate extends Template { template() => """
<title>$title</title>
<h1>$title</h1>
""";}
Finally, use it!
final renderedText = new MyTemplate().evaluate({"title": "Hello, world"})

Related

Can I use #section within a shared template in Razor? [duplicate]

I have this section defined in my _Layout.cshtml
#RenderSection("Scripts", false)
I can easily use it from a view:
#section Scripts {
#*Stuff comes here*#
}
What I'm struggling with is how to get some content injected inside this section from a partial view.
Let's assume this is my view page:
#section Scripts {
<script>
//code comes here
</script>
}
<div>
poo bar poo
</div>
<div>
#Html.Partial("_myPartial")
</div>
I need to inject some content inside the Scripts section from _myPartial partial view.
How can I do this?
Sections don't work in partial views and that's by design. You may use some custom helpers to achieve similar behavior, but honestly it's the view's responsibility to include the necessary scripts, not the partial's responsibility. I would recommend using the #scripts section of the main view to do that and not have the partials worry about scripts.
This is quite a popular question, so I'll post my solution up.
I had the same problem and although it isn't ideal, I think it actually works quite well and doesn't make the partial dependant on the view.
My scenario was that an action was accessible by itself but also could be embedded into a a view - a google map.
In my _layout I have:
#RenderSection("body_scripts", false)
In my index view I have:
#Html.Partial("Clients")
#section body_scripts
{
#Html.Partial("Clients_Scripts")
}
In my clients view I have (all the map and assoc. html):
#section body_scripts
{
#Html.Partial("Clients_Scripts")
}
My Clients_Scripts view contains the javascript to be rendered onto the page.
This way my script is isolated and can be rendered into the page where required, with the body_scripts tag only being rendered on the first occurrence that the razor view engine finds it.
That lets me have everything separated - it's a solution that works quite well for me, others may have issues with it, but it does patch the "by design" hole.
From the solutions in this thread, I came up with the following probably overcomplicated solution that lets you delay rendering any html (scripts too) within a using block.
USAGE
Create the "section"
Typical scenario: In a partial view, only include the block one time no matter how many times the partial view is repeated in the page:
#using (Html.Delayed(isOnlyOne: "some unique name for this section")) {
<script>
someInlineScript();
</script>
}
In a partial view, include the block for every time the partial is used:
#using (Html.Delayed()) {
<b>show me multiple times, #Model.Whatever</b>
}
In a partial view, only include the block once no matter how many times the partial is repeated, but later render it specifically by name when-i-call-you:
#using (Html.Delayed("when-i-call-you", isOnlyOne: "different unique name")) {
<b>show me once by name</b>
<span>#Model.First().Value</span>
}
Render the "sections"
(i.e. display the delayed section in a parent view)
#Html.RenderDelayed(); // writes unnamed sections (#1 and #2, excluding #3)
#Html.RenderDelayed("when-i-call-you", false); // writes the specified block, and ignore the `isOnlyOne` setting so we can dump it again
#Html.RenderDelayed("when-i-call-you"); // render the specified block by name
#Html.RenderDelayed("when-i-call-you"); // since it was "popped" in the last call, won't render anything due to `isOnlyOne` provided in `Html.Delayed`
CODE
public static class HtmlRenderExtensions {
/// <summary>
/// Delegate script/resource/etc injection until the end of the page
/// <para>#via https://stackoverflow.com/a/14127332/1037948 and http://jadnb.wordpress.com/2011/02/16/rendering-scripts-from-partial-views-at-the-end-in-mvc/ </para>
/// </summary>
private class DelayedInjectionBlock : IDisposable {
/// <summary>
/// Unique internal storage key
/// </summary>
private const string CACHE_KEY = "DCCF8C78-2E36-4567-B0CF-FE052ACCE309"; // "DelayedInjectionBlocks";
/// <summary>
/// Internal storage identifier for remembering unique/isOnlyOne items
/// </summary>
private const string UNIQUE_IDENTIFIER_KEY = CACHE_KEY;
/// <summary>
/// What to use as internal storage identifier if no identifier provided (since we can't use null as key)
/// </summary>
private const string EMPTY_IDENTIFIER = "";
/// <summary>
/// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="identifier">optional unique sub-identifier for a given injection block</param>
/// <returns>list of delayed-execution callbacks to render internal content</returns>
public static Queue<string> GetQueue(HtmlHelper helper, string identifier = null) {
return _GetOrSet(helper, new Queue<string>(), identifier ?? EMPTY_IDENTIFIER);
}
/// <summary>
/// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="defaultValue">the default value to return if the cached item isn't found or isn't the expected type; can also be used to set with an arbitrary value</param>
/// <param name="identifier">optional unique sub-identifier for a given injection block</param>
/// <returns>list of delayed-execution callbacks to render internal content</returns>
private static T _GetOrSet<T>(HtmlHelper helper, T defaultValue, string identifier = EMPTY_IDENTIFIER) where T : class {
var storage = GetStorage(helper);
// return the stored item, or set it if it does not exist
return (T) (storage.ContainsKey(identifier) ? storage[identifier] : (storage[identifier] = defaultValue));
}
/// <summary>
/// Get the storage, but if it doesn't exist or isn't the expected type, then create a new "bucket"
/// </summary>
/// <param name="helper"></param>
/// <returns></returns>
public static Dictionary<string, object> GetStorage(HtmlHelper helper) {
var storage = helper.ViewContext.HttpContext.Items[CACHE_KEY] as Dictionary<string, object>;
if (storage == null) helper.ViewContext.HttpContext.Items[CACHE_KEY] = (storage = new Dictionary<string, object>());
return storage;
}
private readonly HtmlHelper helper;
private readonly string identifier;
private readonly string isOnlyOne;
/// <summary>
/// Create a new using block from the given helper (used for trapping appropriate context)
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="identifier">optional unique identifier to specify one or many injection blocks</param>
/// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
public DelayedInjectionBlock(HtmlHelper helper, string identifier = null, string isOnlyOne = null) {
this.helper = helper;
// start a new writing context
((WebViewPage)this.helper.ViewDataContainer).OutputStack.Push(new StringWriter());
this.identifier = identifier ?? EMPTY_IDENTIFIER;
this.isOnlyOne = isOnlyOne;
}
/// <summary>
/// Append the internal content to the context's cached list of output delegates
/// </summary>
public void Dispose() {
// render the internal content of the injection block helper
// make sure to pop from the stack rather than just render from the Writer
// so it will remove it from regular rendering
var content = ((WebViewPage)this.helper.ViewDataContainer).OutputStack;
var renderedContent = content.Count == 0 ? string.Empty : content.Pop().ToString();
// if we only want one, remove the existing
var queue = GetQueue(this.helper, this.identifier);
// get the index of the existing item from the alternate storage
var existingIdentifiers = _GetOrSet(this.helper, new Dictionary<string, int>(), UNIQUE_IDENTIFIER_KEY);
// only save the result if this isn't meant to be unique, or
// if it's supposed to be unique and we haven't encountered this identifier before
if( null == this.isOnlyOne || !existingIdentifiers.ContainsKey(this.isOnlyOne) ) {
// remove the new writing context we created for this block
// and save the output to the queue for later
queue.Enqueue(renderedContent);
// only remember this if supposed to
if(null != this.isOnlyOne) existingIdentifiers[this.isOnlyOne] = queue.Count; // save the index, so we could remove it directly (if we want to use the last instance of the block rather than the first)
}
}
}
/// <summary>
/// <para>Start a delayed-execution block of output -- this will be rendered/printed on the next call to <see cref="RenderDelayed"/>.</para>
/// <para>
/// <example>
/// Print once in "default block" (usually rendered at end via <code>#Html.RenderDelayed()</code>). Code:
/// <code>
/// #using (Html.Delayed()) {
/// <b>show at later</b>
/// <span>#Model.Name</span>
/// etc
/// }
/// </code>
/// </example>
/// </para>
/// <para>
/// <example>
/// Print once (i.e. if within a looped partial), using identified block via <code>#Html.RenderDelayed("one-time")</code>. Code:
/// <code>
/// #using (Html.Delayed("one-time", isOnlyOne: "one-time")) {
/// <b>show me once</b>
/// <span>#Model.First().Value</span>
/// }
/// </code>
/// </example>
/// </para>
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
/// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
/// <returns>using block to wrap delayed output</returns>
public static IDisposable Delayed(this HtmlHelper helper, string injectionBlockId = null, string isOnlyOne = null) {
return new DelayedInjectionBlock(helper, injectionBlockId, isOnlyOne);
}
/// <summary>
/// Render all queued output blocks injected via <see cref="Delayed"/>.
/// <para>
/// <example>
/// Print all delayed blocks using default identifier (i.e. not provided)
/// <code>
/// #using (Html.Delayed()) {
/// <b>show me later</b>
/// <span>#Model.Name</span>
/// etc
/// }
/// </code>
/// -- then later --
/// <code>
/// #using (Html.Delayed()) {
/// <b>more for later</b>
/// etc
/// }
/// </code>
/// -- then later --
/// <code>
/// #Html.RenderDelayed() // will print both delayed blocks
/// </code>
/// </example>
/// </para>
/// <para>
/// <example>
/// Allow multiple repetitions of rendered blocks, using same <code>#Html.Delayed()...</code> as before. Code:
/// <code>
/// #Html.RenderDelayed(removeAfterRendering: false); /* will print */
/// #Html.RenderDelayed() /* will print again because not removed before */
/// </code>
/// </example>
/// </para>
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
/// <param name="removeAfterRendering">only render this once</param>
/// <returns>rendered output content</returns>
public static MvcHtmlString RenderDelayed(this HtmlHelper helper, string injectionBlockId = null, bool removeAfterRendering = true) {
var stack = DelayedInjectionBlock.GetQueue(helper, injectionBlockId);
if( removeAfterRendering ) {
var sb = new StringBuilder(
#if DEBUG
string.Format("<!-- delayed-block: {0} -->", injectionBlockId)
#endif
);
// .count faster than .any
while (stack.Count > 0) {
sb.AppendLine(stack.Dequeue());
}
return MvcHtmlString.Create(sb.ToString());
}
return MvcHtmlString.Create(
#if DEBUG
string.Format("<!-- delayed-block: {0} -->", injectionBlockId) +
#endif
string.Join(Environment.NewLine, stack));
}
}
If you do have a legitimate need to run some js from a partial, here's how you could do it, jQuery is required:
<script type="text/javascript">
function scriptToExecute()
{
//The script you want to execute when page is ready.
}
function runWhenReady()
{
if (window.$)
scriptToExecute();
else
setTimeout(runWhenReady, 100);
}
runWhenReady();
</script>
The goal of the OP is that he wants to define inline scripts into his Partial View, which I assume that this script is specific only to that Partial View, and have that block included into his script section.
I get that he wants to have that Partial View to be self contained. The idea is similar to components when using Angular.
My way would be to just keep the scripts inside the Partial View as is. Now the problem with that is when calling Partial View, it may execute the script in there before all other scripts (which is typically added to the bottom of the layout page). In that case, you just have the Partial View script wait for the other scripts. There are several ways to do this. The simplest one, which I've used before, is using an event on body.
On my layout, I would have something on the bottom like this:
// global scripts
<script src="js/jquery.min.js"></script>
// view scripts
#RenderSection("scripts", false)
// then finally trigger partial view scripts
<script>
(function(){
document.querySelector('body').dispatchEvent(new Event('scriptsLoaded'));
})();
</script>
Then on my Partial View (at the bottom):
<script>
(function(){
document.querySelector('body').addEventListener('scriptsLoaded', function() {
// .. do your thing here
});
})();
</script>
Another solution is using a stack to push all your scripts, and call each one at the end. Other solution, as mentioned already, is RequireJS/AMD pattern, which works really well also.
Following the unobtrusive principle, it's not quite required for "_myPartial" to inject content directly into scripts section. You could add those partial view scripts into separate .js file and reference them into #scripts section from parent view.
There is a fundamental flaw in the way we think about web, especially when using MVC. The flaw is that JavaScript is somehow the view's responsibility. A view is a view, JavaScript (behavioral or otherwise) is JavaScript. In Silverlight and WPF's MVVM pattern we we're faced with "view first" or "model first". In MVC we should always try to reason from the model's standpoint and JavaScript is a part of this model in many ways.
I would suggest using the AMD pattern (I myself like RequireJS). Seperate your JavaScript in modules, define your functionality and hook into your html from JavaScript instead of relying on a view to load the JavaScript. This will clean up your code, seperate your concerns and make life easier all in one fell swoop.
This worked for me allowing me to co-locate javascript and html for partial view in same file. Helps with thought process to see html and related part in same partial view file.
In View which uses Partial View called "_MyPartialView.cshtml"
<div>
#Html.Partial("_MyPartialView",< model for partial view>,
new ViewDataDictionary { { "Region", "HTMLSection" } } })
</div>
#section scripts{
#Html.Partial("_MyPartialView",<model for partial view>,
new ViewDataDictionary { { "Region", "ScriptSection" } })
}
In Partial View file
#model SomeType
#{
var region = ViewData["Region"] as string;
}
#if (region == "HTMLSection")
{
}
#if (region == "ScriptSection")
{
<script type="text/javascript">
</script">
}
The first solution I can think of, is to use ViewBag to store the values that must be rendered.
Onestly I never tried if this work from a partial view, but it should imo.
You can't need using sections in partial view.
Include in your Partial View.
It execute the function after jQuery loaded.
You can alter de condition clause for your code.
<script type="text/javascript">
var time = setInterval(function () {
if (window.jQuery != undefined) {
window.clearInterval(time);
//Begin
$(document).ready(function () {
//....
});
//End
};
}, 10); </script>
Julio Spader
You can use these Extension Methods: (Save as PartialWithScript.cs)
namespace System.Web.Mvc.Html
{
public static class PartialWithScript
{
public static void RenderPartialWithScript(this HtmlHelper htmlHelper, string partialViewName)
{
if (htmlHelper.ViewBag.ScriptPartials == null)
{
htmlHelper.ViewBag.ScriptPartials = new List<string>();
}
if (!htmlHelper.ViewBag.ScriptPartials.Contains(partialViewName))
{
htmlHelper.ViewBag.ScriptPartials.Add(partialViewName);
}
htmlHelper.ViewBag.ScriptPartialHtml = true;
htmlHelper.RenderPartial(partialViewName);
}
public static void RenderPartialScripts(this HtmlHelper htmlHelper)
{
if (htmlHelper.ViewBag.ScriptPartials != null)
{
htmlHelper.ViewBag.ScriptPartialHtml = false;
foreach (string partial in htmlHelper.ViewBag.ScriptPartials)
{
htmlHelper.RenderPartial(partial);
}
}
}
}
}
Use like this:
Example partial: (_MyPartial.cshtml)
Put the html in the if, and the js in the else.
#if (ViewBag.ScriptPartialHtml ?? true)
<p>I has htmls</p>
}
else {
<script type="text/javascript">
alert('I has javascripts');
</script>
}
In your _Layout.cshtml, or wherever you want the scripts from the partials on to be rendered, put the following (once): It will render only the javascript of all partials on the current page at this location.
#{ Html.RenderPartialScripts(); }
Then to use your partial, simply do this: It will render only the html at this location.
#{Html.RenderPartialWithScript("~/Views/MyController/_MyPartial.cshtml");}
Pluto's idea in a nicer way:
CustomWebViewPage.cs:
public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> {
public IHtmlString PartialWithScripts(string partialViewName, object model) {
return Html.Partial(partialViewName: partialViewName, model: model, viewData: new ViewDataDictionary { ["view"] = this, ["html"] = Html });
}
public void RenderScriptsInBasePage(HelperResult scripts) {
var parentView = ViewBag.view as WebPageBase;
var parentHtml = ViewBag.html as HtmlHelper;
parentView.DefineSection("scripts", () => {
parentHtml.ViewContext.Writer.Write(scripts.ToHtmlString());
});
}
}
Views\web.config:
<pages pageBaseType="Web.Helpers.CustomWebViewPage">
View:
#PartialWithScripts("_BackendSearchForm")
Partial (_BackendSearchForm.cshtml):
#{ RenderScriptsInBasePage(scripts()); }
#helper scripts() {
<script>
//code will be rendered in a "scripts" section of the Layout page
</script>
}
Layout page:
#RenderSection("scripts", required: false)
There is a way to insert sections in partial views, though it's not pretty. You need to have access to two variables from the parent View. Since part of your partial view's very purpose is to create that section, it makes sense to require these variables.
Here's what it looks like to insert a section in the partial view:
#model KeyValuePair<WebPageBase, HtmlHelper>
#{
Model.Key.DefineSection("SectionNameGoesHere", () =>
{
Model.Value.ViewContext.Writer.Write("Test");
});
}
And in the page inserting the partial view...
#Html.Partial(new KeyValuePair<WebPageBase, HtmlHelper>(this, Html))
You can also use this technique to define the contents of a section programmatically in any class.
Enjoy!
Using Mvc Core you can create a tidy TagHelper scripts as seen below. This could easily be morphed into a section tag where you give it a name as well (or the name is taken from the derived type). Note that dependency injection needs to be setup for IHttpContextAccessor.
When adding scripts (e.g. in a partial)
<scripts>
<script type="text/javascript">
//anything here
</script>
</scripts>
When outputting the scripts (e.g. in a layout file)
<scripts render="true"></scripts>
Code
public class ScriptsTagHelper : TagHelper
{
private static readonly object ITEMSKEY = new Object();
private IDictionary<object, object> _items => _httpContextAccessor?.HttpContext?.Items;
private IHttpContextAccessor _httpContextAccessor;
public ScriptsTagHelper(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var attribute = (TagHelperAttribute)null;
context.AllAttributes.TryGetAttribute("render",out attribute);
var render = false;
if(attribute != null)
{
render = Convert.ToBoolean(attribute.Value.ToString());
}
if (render)
{
if (_items.ContainsKey(ITEMSKEY))
{
var scripts = _items[ITEMSKEY] as List<HtmlString>;
var content = String.Concat(scripts);
output.Content.SetHtmlContent(content);
}
}
else
{
List<HtmlString> list = null;
if (!_items.ContainsKey(ITEMSKEY))
{
list = new List<HtmlString>();
_items[ITEMSKEY] = list;
}
list = _items[ITEMSKEY] as List<HtmlString>;
var content = await output.GetChildContentAsync();
list.Add(new HtmlString(content.GetContent()));
}
}
}
I had this issue today. I'll add a workaround that uses <script defer> as I didn't see the other answers mention it.
//on a JS file somewhere (i.e partial-view-caller.js)
(() => <your partial view script>)();
//in your Partial View
<script src="~/partial-view-caller.js" defer></script>
//you can actually just straight call your partial view script living in an external file - I just prefer having an initialization method :)
Code above is an excerpt from a quick post I made about this question.
I solved this a completely different route (because I was in a hurry and didn't want to implement a new HtmlHelper):
I wrapped my Partial View in a big if-else statement:
#if ((bool)ViewData["ShouldRenderScripts"] == true){
// Scripts
}else{
// Html
}
Then, I called the Partial twice with a custom ViewData:
#Html.Partial("MyPartialView", Model,
new ViewDataDictionary { { "ShouldRenderScripts", false } })
#section scripts{
#Html.Partial("MyPartialView", Model,
new ViewDataDictionary { { "ShouldRenderScripts", true } })
}
I had a similar problem, where I had a master page as follows:
#section Scripts {
<script>
$(document).ready(function () {
...
});
</script>
}
...
#Html.Partial("_Charts", Model)
but the partial view depended on some JavaScript in the Scripts section. I solved it by encoding the partial view as JSON, loading it into a JavaScript variable and then using this to populate a div, so:
#{
var partial = Html.Raw(Json.Encode(new { html = Html.Partial("_Charts", Model).ToString() }));
}
#section Scripts {
<script>
$(document).ready(function () {
...
var partial = #partial;
$('#partial').html(partial.html);
});
</script>
}
<div id="partial"></div>
choicely, you could use a your Folder/index.cshtml as a masterpage then add section scripts. Then, in your layout you have:
#RenderSection("scripts", required: false)
and your index.cshtml:
#section scripts{
#Scripts.Render("~/Scripts/file.js")
}
and it will working over all your partialviews. It work for me
My solution was to load the script from the layout page. Then in the javacript, check for the presence of one of the elements in the parial view. If the element was present, the javascript knew that the partial had been included.
$(document).ready(function () {
var joinButton = $("#join");
if (joinButton.length != 0) {
// the partial is present
// execute the relevant code
}
});
Well, I guess the other posters have provided you with a means to directly include an #section within your partial (by using 3rd party html helpers).
But, I reckon that, if your script is tightly coupled to your partial, just put your javascript directly inside an inline <script> tag within your partial and be done with it (just be careful of script duplication if you intend on using the partial more than once in a single view);
assume you have a partial view called _contact.cshtml, your contact can be a legal (name) or a physical subject (first name, lastname). your view should take care about what's rendered and that can be achived with javascript. so delayed rendering and JS inside view may be needed.
the only way i think, how it can be ommitted, is when we create an unobtrusive way of handling such UI concerns.
also note that MVC 6 will have a so called View Component, even MVC futures had some similar stuff and Telerik also supports such a thing...
I have just added this code on my partial view and solved the problem, though not very clean, it works. You have to make sure the the Ids of the objects you are rendering.
<script>
$(document).ready(function () {
$("#Profile_ProfileID").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#TitleID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#CityID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#GenderID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#PackageID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
});
</script>
I had the similar problem solved it with this:
#section ***{
#RenderSection("****", required: false)
}
Thats a pretty way to inject i guesse.

Struts2 autogenerated dropdownlist doesn't refresh new items on the second select

I have try to implement a form with two select on my form, with doubleselect tag of struts 2, where the content of the second select is conditioned from the first. So surfing the net, i have found the post : http://www.mkyong.com/struts2/struts-2-sdoubleselect-example/, i have try the example suggested by the blogger, but when i choose an element from the first select, the second select did not change it's value.
So, i have debbuged it with firebug on mozilla 17.01 and the javascript autogenerated with the jsp tag doubleselect seems good, cause i have any error into the console. Debugging the code autogenerated with the struts 2 tag, s:doubleselect, i have saw that option element are removed well, but maybe the second select is not refreshed. So for example on the example, when the page is in the firse select i have .net language and in the second .sharp and .vnet, when in the first i choose java, onChange, onDebugg the function that permits to change items to the second select is trigger, the old options are deleted , and the new options are created ad inserted in the the second, but the content of the second select did not change on the page.
So on the link, i have used used the last exampe, programming language:
jsp form
<form:main action="DoubleSelectAction" id="channelerForm">
<s:doubleselect label="Language (Java List) "
id= "Test1"
name="language1"
list="languageMap.keySet()"
doubleId="secondoItem"
doubleName="language2"
doubleList="languageMap.get(top)" />
</form:main>
Define the Action:
public class DoubleSelectAction extends ActionSupport{
private String language1;
private String language2;
Map languageMap;
public String getLanguage1() {
return language1;
}
public void setLanguage1(String language1) {
this.language1 = language1;
}
public String getLanguage2() {
return language2;
}
public void setLanguage2(String language2) {
this.language2 = language2;
}
public Map getLanguageMap() {
return languageMap;
}
public void setLanguageMap(Map languageMap) {
this.languageMap = languageMap;
}
public DoubleSelectAction(){
languageMap =new HashMap();
languageMap.put("Java",
new ArrayList<String>(Arrays.asList("Spring", "Hibernate", "Struts 2")));
languageMap.put(".Net", new ArrayList<String>(Arrays.asList("VB.Net", "C#")));
languageMap.put("JavaScript", new ArrayList<String>(Arrays.asList("jQuery")));
}
public String execute() {
return SUCCESS;
}
public String display() {
return NONE;
}}
So i would like to know if someone has had the same problem,
thanx for yours time.
I think you are trying to wrapping tag inside wrong form tag
I mean to say you might be declared this tagLib (<%# taglib prefix="s" uri="/struts-tags"%>)
you must use the same form rather using form:main tag
I just giving the sample jsp which is successfully rendering .
<%# taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<s:form action="DoubleSelectAction" id="channelerForm">
<s:doubleselect label="Language (Java List) "
id= "Test1"
name="language1"
list="languageMap.keySet()"
doubleId="secondoItem"
doubleName="language2"
doubleList="languageMap.get(top)" />
</s:form>
</body>
</html>
Hope it helps

#Section in PartialView [duplicate]

I have this section defined in my _Layout.cshtml
#RenderSection("Scripts", false)
I can easily use it from a view:
#section Scripts {
#*Stuff comes here*#
}
What I'm struggling with is how to get some content injected inside this section from a partial view.
Let's assume this is my view page:
#section Scripts {
<script>
//code comes here
</script>
}
<div>
poo bar poo
</div>
<div>
#Html.Partial("_myPartial")
</div>
I need to inject some content inside the Scripts section from _myPartial partial view.
How can I do this?
Sections don't work in partial views and that's by design. You may use some custom helpers to achieve similar behavior, but honestly it's the view's responsibility to include the necessary scripts, not the partial's responsibility. I would recommend using the #scripts section of the main view to do that and not have the partials worry about scripts.
This is quite a popular question, so I'll post my solution up.
I had the same problem and although it isn't ideal, I think it actually works quite well and doesn't make the partial dependant on the view.
My scenario was that an action was accessible by itself but also could be embedded into a a view - a google map.
In my _layout I have:
#RenderSection("body_scripts", false)
In my index view I have:
#Html.Partial("Clients")
#section body_scripts
{
#Html.Partial("Clients_Scripts")
}
In my clients view I have (all the map and assoc. html):
#section body_scripts
{
#Html.Partial("Clients_Scripts")
}
My Clients_Scripts view contains the javascript to be rendered onto the page.
This way my script is isolated and can be rendered into the page where required, with the body_scripts tag only being rendered on the first occurrence that the razor view engine finds it.
That lets me have everything separated - it's a solution that works quite well for me, others may have issues with it, but it does patch the "by design" hole.
From the solutions in this thread, I came up with the following probably overcomplicated solution that lets you delay rendering any html (scripts too) within a using block.
USAGE
Create the "section"
Typical scenario: In a partial view, only include the block one time no matter how many times the partial view is repeated in the page:
#using (Html.Delayed(isOnlyOne: "some unique name for this section")) {
<script>
someInlineScript();
</script>
}
In a partial view, include the block for every time the partial is used:
#using (Html.Delayed()) {
<b>show me multiple times, #Model.Whatever</b>
}
In a partial view, only include the block once no matter how many times the partial is repeated, but later render it specifically by name when-i-call-you:
#using (Html.Delayed("when-i-call-you", isOnlyOne: "different unique name")) {
<b>show me once by name</b>
<span>#Model.First().Value</span>
}
Render the "sections"
(i.e. display the delayed section in a parent view)
#Html.RenderDelayed(); // writes unnamed sections (#1 and #2, excluding #3)
#Html.RenderDelayed("when-i-call-you", false); // writes the specified block, and ignore the `isOnlyOne` setting so we can dump it again
#Html.RenderDelayed("when-i-call-you"); // render the specified block by name
#Html.RenderDelayed("when-i-call-you"); // since it was "popped" in the last call, won't render anything due to `isOnlyOne` provided in `Html.Delayed`
CODE
public static class HtmlRenderExtensions {
/// <summary>
/// Delegate script/resource/etc injection until the end of the page
/// <para>#via https://stackoverflow.com/a/14127332/1037948 and http://jadnb.wordpress.com/2011/02/16/rendering-scripts-from-partial-views-at-the-end-in-mvc/ </para>
/// </summary>
private class DelayedInjectionBlock : IDisposable {
/// <summary>
/// Unique internal storage key
/// </summary>
private const string CACHE_KEY = "DCCF8C78-2E36-4567-B0CF-FE052ACCE309"; // "DelayedInjectionBlocks";
/// <summary>
/// Internal storage identifier for remembering unique/isOnlyOne items
/// </summary>
private const string UNIQUE_IDENTIFIER_KEY = CACHE_KEY;
/// <summary>
/// What to use as internal storage identifier if no identifier provided (since we can't use null as key)
/// </summary>
private const string EMPTY_IDENTIFIER = "";
/// <summary>
/// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="identifier">optional unique sub-identifier for a given injection block</param>
/// <returns>list of delayed-execution callbacks to render internal content</returns>
public static Queue<string> GetQueue(HtmlHelper helper, string identifier = null) {
return _GetOrSet(helper, new Queue<string>(), identifier ?? EMPTY_IDENTIFIER);
}
/// <summary>
/// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="defaultValue">the default value to return if the cached item isn't found or isn't the expected type; can also be used to set with an arbitrary value</param>
/// <param name="identifier">optional unique sub-identifier for a given injection block</param>
/// <returns>list of delayed-execution callbacks to render internal content</returns>
private static T _GetOrSet<T>(HtmlHelper helper, T defaultValue, string identifier = EMPTY_IDENTIFIER) where T : class {
var storage = GetStorage(helper);
// return the stored item, or set it if it does not exist
return (T) (storage.ContainsKey(identifier) ? storage[identifier] : (storage[identifier] = defaultValue));
}
/// <summary>
/// Get the storage, but if it doesn't exist or isn't the expected type, then create a new "bucket"
/// </summary>
/// <param name="helper"></param>
/// <returns></returns>
public static Dictionary<string, object> GetStorage(HtmlHelper helper) {
var storage = helper.ViewContext.HttpContext.Items[CACHE_KEY] as Dictionary<string, object>;
if (storage == null) helper.ViewContext.HttpContext.Items[CACHE_KEY] = (storage = new Dictionary<string, object>());
return storage;
}
private readonly HtmlHelper helper;
private readonly string identifier;
private readonly string isOnlyOne;
/// <summary>
/// Create a new using block from the given helper (used for trapping appropriate context)
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="identifier">optional unique identifier to specify one or many injection blocks</param>
/// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
public DelayedInjectionBlock(HtmlHelper helper, string identifier = null, string isOnlyOne = null) {
this.helper = helper;
// start a new writing context
((WebViewPage)this.helper.ViewDataContainer).OutputStack.Push(new StringWriter());
this.identifier = identifier ?? EMPTY_IDENTIFIER;
this.isOnlyOne = isOnlyOne;
}
/// <summary>
/// Append the internal content to the context's cached list of output delegates
/// </summary>
public void Dispose() {
// render the internal content of the injection block helper
// make sure to pop from the stack rather than just render from the Writer
// so it will remove it from regular rendering
var content = ((WebViewPage)this.helper.ViewDataContainer).OutputStack;
var renderedContent = content.Count == 0 ? string.Empty : content.Pop().ToString();
// if we only want one, remove the existing
var queue = GetQueue(this.helper, this.identifier);
// get the index of the existing item from the alternate storage
var existingIdentifiers = _GetOrSet(this.helper, new Dictionary<string, int>(), UNIQUE_IDENTIFIER_KEY);
// only save the result if this isn't meant to be unique, or
// if it's supposed to be unique and we haven't encountered this identifier before
if( null == this.isOnlyOne || !existingIdentifiers.ContainsKey(this.isOnlyOne) ) {
// remove the new writing context we created for this block
// and save the output to the queue for later
queue.Enqueue(renderedContent);
// only remember this if supposed to
if(null != this.isOnlyOne) existingIdentifiers[this.isOnlyOne] = queue.Count; // save the index, so we could remove it directly (if we want to use the last instance of the block rather than the first)
}
}
}
/// <summary>
/// <para>Start a delayed-execution block of output -- this will be rendered/printed on the next call to <see cref="RenderDelayed"/>.</para>
/// <para>
/// <example>
/// Print once in "default block" (usually rendered at end via <code>#Html.RenderDelayed()</code>). Code:
/// <code>
/// #using (Html.Delayed()) {
/// <b>show at later</b>
/// <span>#Model.Name</span>
/// etc
/// }
/// </code>
/// </example>
/// </para>
/// <para>
/// <example>
/// Print once (i.e. if within a looped partial), using identified block via <code>#Html.RenderDelayed("one-time")</code>. Code:
/// <code>
/// #using (Html.Delayed("one-time", isOnlyOne: "one-time")) {
/// <b>show me once</b>
/// <span>#Model.First().Value</span>
/// }
/// </code>
/// </example>
/// </para>
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
/// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
/// <returns>using block to wrap delayed output</returns>
public static IDisposable Delayed(this HtmlHelper helper, string injectionBlockId = null, string isOnlyOne = null) {
return new DelayedInjectionBlock(helper, injectionBlockId, isOnlyOne);
}
/// <summary>
/// Render all queued output blocks injected via <see cref="Delayed"/>.
/// <para>
/// <example>
/// Print all delayed blocks using default identifier (i.e. not provided)
/// <code>
/// #using (Html.Delayed()) {
/// <b>show me later</b>
/// <span>#Model.Name</span>
/// etc
/// }
/// </code>
/// -- then later --
/// <code>
/// #using (Html.Delayed()) {
/// <b>more for later</b>
/// etc
/// }
/// </code>
/// -- then later --
/// <code>
/// #Html.RenderDelayed() // will print both delayed blocks
/// </code>
/// </example>
/// </para>
/// <para>
/// <example>
/// Allow multiple repetitions of rendered blocks, using same <code>#Html.Delayed()...</code> as before. Code:
/// <code>
/// #Html.RenderDelayed(removeAfterRendering: false); /* will print */
/// #Html.RenderDelayed() /* will print again because not removed before */
/// </code>
/// </example>
/// </para>
/// </summary>
/// <param name="helper">the helper from which we use the context</param>
/// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
/// <param name="removeAfterRendering">only render this once</param>
/// <returns>rendered output content</returns>
public static MvcHtmlString RenderDelayed(this HtmlHelper helper, string injectionBlockId = null, bool removeAfterRendering = true) {
var stack = DelayedInjectionBlock.GetQueue(helper, injectionBlockId);
if( removeAfterRendering ) {
var sb = new StringBuilder(
#if DEBUG
string.Format("<!-- delayed-block: {0} -->", injectionBlockId)
#endif
);
// .count faster than .any
while (stack.Count > 0) {
sb.AppendLine(stack.Dequeue());
}
return MvcHtmlString.Create(sb.ToString());
}
return MvcHtmlString.Create(
#if DEBUG
string.Format("<!-- delayed-block: {0} -->", injectionBlockId) +
#endif
string.Join(Environment.NewLine, stack));
}
}
If you do have a legitimate need to run some js from a partial, here's how you could do it, jQuery is required:
<script type="text/javascript">
function scriptToExecute()
{
//The script you want to execute when page is ready.
}
function runWhenReady()
{
if (window.$)
scriptToExecute();
else
setTimeout(runWhenReady, 100);
}
runWhenReady();
</script>
The goal of the OP is that he wants to define inline scripts into his Partial View, which I assume that this script is specific only to that Partial View, and have that block included into his script section.
I get that he wants to have that Partial View to be self contained. The idea is similar to components when using Angular.
My way would be to just keep the scripts inside the Partial View as is. Now the problem with that is when calling Partial View, it may execute the script in there before all other scripts (which is typically added to the bottom of the layout page). In that case, you just have the Partial View script wait for the other scripts. There are several ways to do this. The simplest one, which I've used before, is using an event on body.
On my layout, I would have something on the bottom like this:
// global scripts
<script src="js/jquery.min.js"></script>
// view scripts
#RenderSection("scripts", false)
// then finally trigger partial view scripts
<script>
(function(){
document.querySelector('body').dispatchEvent(new Event('scriptsLoaded'));
})();
</script>
Then on my Partial View (at the bottom):
<script>
(function(){
document.querySelector('body').addEventListener('scriptsLoaded', function() {
// .. do your thing here
});
})();
</script>
Another solution is using a stack to push all your scripts, and call each one at the end. Other solution, as mentioned already, is RequireJS/AMD pattern, which works really well also.
Following the unobtrusive principle, it's not quite required for "_myPartial" to inject content directly into scripts section. You could add those partial view scripts into separate .js file and reference them into #scripts section from parent view.
There is a fundamental flaw in the way we think about web, especially when using MVC. The flaw is that JavaScript is somehow the view's responsibility. A view is a view, JavaScript (behavioral or otherwise) is JavaScript. In Silverlight and WPF's MVVM pattern we we're faced with "view first" or "model first". In MVC we should always try to reason from the model's standpoint and JavaScript is a part of this model in many ways.
I would suggest using the AMD pattern (I myself like RequireJS). Seperate your JavaScript in modules, define your functionality and hook into your html from JavaScript instead of relying on a view to load the JavaScript. This will clean up your code, seperate your concerns and make life easier all in one fell swoop.
This worked for me allowing me to co-locate javascript and html for partial view in same file. Helps with thought process to see html and related part in same partial view file.
In View which uses Partial View called "_MyPartialView.cshtml"
<div>
#Html.Partial("_MyPartialView",< model for partial view>,
new ViewDataDictionary { { "Region", "HTMLSection" } } })
</div>
#section scripts{
#Html.Partial("_MyPartialView",<model for partial view>,
new ViewDataDictionary { { "Region", "ScriptSection" } })
}
In Partial View file
#model SomeType
#{
var region = ViewData["Region"] as string;
}
#if (region == "HTMLSection")
{
}
#if (region == "ScriptSection")
{
<script type="text/javascript">
</script">
}
The first solution I can think of, is to use ViewBag to store the values that must be rendered.
Onestly I never tried if this work from a partial view, but it should imo.
You can't need using sections in partial view.
Include in your Partial View.
It execute the function after jQuery loaded.
You can alter de condition clause for your code.
<script type="text/javascript">
var time = setInterval(function () {
if (window.jQuery != undefined) {
window.clearInterval(time);
//Begin
$(document).ready(function () {
//....
});
//End
};
}, 10); </script>
Julio Spader
You can use these Extension Methods: (Save as PartialWithScript.cs)
namespace System.Web.Mvc.Html
{
public static class PartialWithScript
{
public static void RenderPartialWithScript(this HtmlHelper htmlHelper, string partialViewName)
{
if (htmlHelper.ViewBag.ScriptPartials == null)
{
htmlHelper.ViewBag.ScriptPartials = new List<string>();
}
if (!htmlHelper.ViewBag.ScriptPartials.Contains(partialViewName))
{
htmlHelper.ViewBag.ScriptPartials.Add(partialViewName);
}
htmlHelper.ViewBag.ScriptPartialHtml = true;
htmlHelper.RenderPartial(partialViewName);
}
public static void RenderPartialScripts(this HtmlHelper htmlHelper)
{
if (htmlHelper.ViewBag.ScriptPartials != null)
{
htmlHelper.ViewBag.ScriptPartialHtml = false;
foreach (string partial in htmlHelper.ViewBag.ScriptPartials)
{
htmlHelper.RenderPartial(partial);
}
}
}
}
}
Use like this:
Example partial: (_MyPartial.cshtml)
Put the html in the if, and the js in the else.
#if (ViewBag.ScriptPartialHtml ?? true)
<p>I has htmls</p>
}
else {
<script type="text/javascript">
alert('I has javascripts');
</script>
}
In your _Layout.cshtml, or wherever you want the scripts from the partials on to be rendered, put the following (once): It will render only the javascript of all partials on the current page at this location.
#{ Html.RenderPartialScripts(); }
Then to use your partial, simply do this: It will render only the html at this location.
#{Html.RenderPartialWithScript("~/Views/MyController/_MyPartial.cshtml");}
Pluto's idea in a nicer way:
CustomWebViewPage.cs:
public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> {
public IHtmlString PartialWithScripts(string partialViewName, object model) {
return Html.Partial(partialViewName: partialViewName, model: model, viewData: new ViewDataDictionary { ["view"] = this, ["html"] = Html });
}
public void RenderScriptsInBasePage(HelperResult scripts) {
var parentView = ViewBag.view as WebPageBase;
var parentHtml = ViewBag.html as HtmlHelper;
parentView.DefineSection("scripts", () => {
parentHtml.ViewContext.Writer.Write(scripts.ToHtmlString());
});
}
}
Views\web.config:
<pages pageBaseType="Web.Helpers.CustomWebViewPage">
View:
#PartialWithScripts("_BackendSearchForm")
Partial (_BackendSearchForm.cshtml):
#{ RenderScriptsInBasePage(scripts()); }
#helper scripts() {
<script>
//code will be rendered in a "scripts" section of the Layout page
</script>
}
Layout page:
#RenderSection("scripts", required: false)
There is a way to insert sections in partial views, though it's not pretty. You need to have access to two variables from the parent View. Since part of your partial view's very purpose is to create that section, it makes sense to require these variables.
Here's what it looks like to insert a section in the partial view:
#model KeyValuePair<WebPageBase, HtmlHelper>
#{
Model.Key.DefineSection("SectionNameGoesHere", () =>
{
Model.Value.ViewContext.Writer.Write("Test");
});
}
And in the page inserting the partial view...
#Html.Partial(new KeyValuePair<WebPageBase, HtmlHelper>(this, Html))
You can also use this technique to define the contents of a section programmatically in any class.
Enjoy!
Using Mvc Core you can create a tidy TagHelper scripts as seen below. This could easily be morphed into a section tag where you give it a name as well (or the name is taken from the derived type). Note that dependency injection needs to be setup for IHttpContextAccessor.
When adding scripts (e.g. in a partial)
<scripts>
<script type="text/javascript">
//anything here
</script>
</scripts>
When outputting the scripts (e.g. in a layout file)
<scripts render="true"></scripts>
Code
public class ScriptsTagHelper : TagHelper
{
private static readonly object ITEMSKEY = new Object();
private IDictionary<object, object> _items => _httpContextAccessor?.HttpContext?.Items;
private IHttpContextAccessor _httpContextAccessor;
public ScriptsTagHelper(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var attribute = (TagHelperAttribute)null;
context.AllAttributes.TryGetAttribute("render",out attribute);
var render = false;
if(attribute != null)
{
render = Convert.ToBoolean(attribute.Value.ToString());
}
if (render)
{
if (_items.ContainsKey(ITEMSKEY))
{
var scripts = _items[ITEMSKEY] as List<HtmlString>;
var content = String.Concat(scripts);
output.Content.SetHtmlContent(content);
}
}
else
{
List<HtmlString> list = null;
if (!_items.ContainsKey(ITEMSKEY))
{
list = new List<HtmlString>();
_items[ITEMSKEY] = list;
}
list = _items[ITEMSKEY] as List<HtmlString>;
var content = await output.GetChildContentAsync();
list.Add(new HtmlString(content.GetContent()));
}
}
}
I had this issue today. I'll add a workaround that uses <script defer> as I didn't see the other answers mention it.
//on a JS file somewhere (i.e partial-view-caller.js)
(() => <your partial view script>)();
//in your Partial View
<script src="~/partial-view-caller.js" defer></script>
//you can actually just straight call your partial view script living in an external file - I just prefer having an initialization method :)
Code above is an excerpt from a quick post I made about this question.
I solved this a completely different route (because I was in a hurry and didn't want to implement a new HtmlHelper):
I wrapped my Partial View in a big if-else statement:
#if ((bool)ViewData["ShouldRenderScripts"] == true){
// Scripts
}else{
// Html
}
Then, I called the Partial twice with a custom ViewData:
#Html.Partial("MyPartialView", Model,
new ViewDataDictionary { { "ShouldRenderScripts", false } })
#section scripts{
#Html.Partial("MyPartialView", Model,
new ViewDataDictionary { { "ShouldRenderScripts", true } })
}
I had a similar problem, where I had a master page as follows:
#section Scripts {
<script>
$(document).ready(function () {
...
});
</script>
}
...
#Html.Partial("_Charts", Model)
but the partial view depended on some JavaScript in the Scripts section. I solved it by encoding the partial view as JSON, loading it into a JavaScript variable and then using this to populate a div, so:
#{
var partial = Html.Raw(Json.Encode(new { html = Html.Partial("_Charts", Model).ToString() }));
}
#section Scripts {
<script>
$(document).ready(function () {
...
var partial = #partial;
$('#partial').html(partial.html);
});
</script>
}
<div id="partial"></div>
choicely, you could use a your Folder/index.cshtml as a masterpage then add section scripts. Then, in your layout you have:
#RenderSection("scripts", required: false)
and your index.cshtml:
#section scripts{
#Scripts.Render("~/Scripts/file.js")
}
and it will working over all your partialviews. It work for me
My solution was to load the script from the layout page. Then in the javacript, check for the presence of one of the elements in the parial view. If the element was present, the javascript knew that the partial had been included.
$(document).ready(function () {
var joinButton = $("#join");
if (joinButton.length != 0) {
// the partial is present
// execute the relevant code
}
});
Well, I guess the other posters have provided you with a means to directly include an #section within your partial (by using 3rd party html helpers).
But, I reckon that, if your script is tightly coupled to your partial, just put your javascript directly inside an inline <script> tag within your partial and be done with it (just be careful of script duplication if you intend on using the partial more than once in a single view);
assume you have a partial view called _contact.cshtml, your contact can be a legal (name) or a physical subject (first name, lastname). your view should take care about what's rendered and that can be achived with javascript. so delayed rendering and JS inside view may be needed.
the only way i think, how it can be ommitted, is when we create an unobtrusive way of handling such UI concerns.
also note that MVC 6 will have a so called View Component, even MVC futures had some similar stuff and Telerik also supports such a thing...
I have just added this code on my partial view and solved the problem, though not very clean, it works. You have to make sure the the Ids of the objects you are rendering.
<script>
$(document).ready(function () {
$("#Profile_ProfileID").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#TitleID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#CityID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#GenderID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
$("#PackageID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
});
</script>
I had the similar problem solved it with this:
#section ***{
#RenderSection("****", required: false)
}
Thats a pretty way to inject i guesse.

Transforming output of a #helper in ASP.NET MVC Razor view

Is it possible to implement a custom transformation on the output of a #helper? My point is to arrive at a solution that would allow me to have something along these lines:
#helper RenderCombinedStylesheetsWithColorOverride(string color)
{
<link rel="stylesheet" type="text/css" href="menu.css" />
<link rel="stylesheet" type="text/css" href="site.css" />
<style type="text/css">
* { color: #color; }
</style>
}
The twist is in the name of the helper (RenderCombinedStylesheets...), which hints at what I'd like to do here. That is, take the normal HTML-encoded output of the helper, and pipe it through my custom code. In there, I'd like to take it apart and then reassemble it so that the final output is a single <link rel="stylesheet" ... /> reference to a generated combined and minified css file.
Note that this is a simplified example! In reality, there are multiple parameters and the output transformation is not limited to merely combining stylesheet fragments. I'd also like to do JavaScript code generation this way.
The main goal is to come up with something that will allow me to apply normal Razor templating to specific sections of my views and then perform additional transformations on those sections before emitting the final output.
Any ideas appreciated!
UPDATE: I've stumbled upon this SO question, which suggests a way to accomplish this is through plain ol' HtmlHelper extensions. It seems I've been having incomplete understanding of what they do, or at least underestimating their power. I'll report back with status on implementation.
Yes! The post I linked in my updated question was spot on! Here's the solution:
public static class ResourceCombiningHelper
{
private static string MakeKey(string type)
{
return "CombinableResource" + (type ?? "").ToLowerInvariant();
}
public static IHtmlString CombinableResource(this HtmlHelper helper, dynamic template, string type)
{
var key = MakeKey(type);
var context = helper.ViewContext.HttpContext;
var resources = (List<dynamic>)context.Items[key];
if (resources == null)
{
resources = new List<dynamic> { template };
context.Items[key] = resources;
}
else
{
resources.Add(template);
}
return new HtmlString(String.Empty);
}
public static IHtmlString RenderCombinableResources(this HtmlHelper helper, string type)
{
var key = MakeKey(type);
var context = helper.ViewContext.HttpContext;
var resources = (List<dynamic>)context.Items[key];
if (resources != null)
{
foreach (var resource in resources)
{
if (resource is HelperResult)
{
// Add in-line content to combined resource here.
}
else if (resource is string)
{
// Add external reference to combined resource here.
}
}
}
// Return a single reference to the combined resource (<link>, <script>, etc.)
}
}
Usage in Razor view:
#helper ColorOverridingStyle(string color)
{
<style type="text/css">
* { color: #color; }
</style>
}
#{ var color = ViewBag.TextColor; }
#Html.CombinableResource(Url.Content("~/Content/site.css"), "css")
#Html.CombinableResource(Url.Content("~/Content/menu.js"), "js")
#Html.CombinableResource(ColorOverridingStyle(color), "css")
And final HTML output example:
<head>
<link href="/Content/combined-css.css" rel="stylesheet" type="text/css" />
<script src="/Content/combined-js.js" type="text/javascript"></script>
</head>
Works great! Off to stretch the limits of this little gem... :)

ASP. Net MVC and RegisterClientScriptBlock alternative

I currently have a web form aspx page that calls RegisterClientScriptBlock. This sends down message text that I use for client side validation e.g.
<script type="text/javascript">
//<![CDATA[
var c_errorMessages = {
RequiredField : "* Mandatory field"
};
//]]>
</script>
The values are generated on the server side based on culture and resource files.
I believe you cannot use RegisterClientScriptBlock with MVC.
Any ideas on how I can achieve this with MVC?
The validation that comes with ASP.NET MVC 2 has built-in support for localized validation messages when using client-side validation. This will take care of registering the client scripts.
Having said that, the most common way to do this in ASP.NET MVC would probably be to simply have the controller feed the view with the data required to render the client script. An example of this would be
Action method in controller:
ViewData["MessagesToClient"] = new[] { "Abandon", "All", "Hope" };
return View("MyView");
Some code in MyView.aspx:
<%= RenderPartial("MyPartialView") %>
Some code in MyPartialView.ascx:
<script>
<% foreach (var message in (IEnumerable<string>)ViewData["MessagesToClient"]) { %>
alert("<%= message %>");
<% } %>
</script>
This way, MyView.aspx doesn't necessarily need to know about the data MyPartialView.ascx needs.
Create an extension method for HtmlHelper which takes your model and renders the javascript.
If you are doing validation:
Have a look at Castle Validation attributes. http://castleproject.org.
You can add attributes to your model (class) ...
[ValidateNonEmpty]
public string Name { get; set; }
and your extension method can determine the presence of these and write the appropriate javascript / jquery.
public static string JSValidation<T>(this HtmlHelper<T> html, T model) where T : class {}
And in your view use the helper:
<%= Html.JSValidation(Model) %>
ASP.NET MVC in Action has a brilliant example of this in Chapter 13.
Thanks for answer bzlm. My solution is pretty much the same as yours except I am not using a user control
In my controller I add to viewdata(this would be generated from method):
ViewData["javascriptBlockRequired"] =
"\r\n<script type='text/javascript'>\r\n//<![CDATA[\r\nvar c_merchant = { \r\n\tSomeField: false};\r\nvar c_errorMessages = {\r\n\tRequiredField : '* Required' \r\n};\r\n//]]>\r\n</script>\r\n";
In my view I output the script at the start of the body:
<body>
<%= ViewData["javascriptBlockRequired"] %>
....
<body/>
1- Add Extentions methods class
public static class Extentions
{
public static void AddRegisterClientsSript(this HtmlHelper helper, string key, string script)
{
Dictionary<string, string> scripts;
if (helper.ViewBag.RegisterClientsSript != null)
{
scripts = (Dictionary<string, string>)helper.ViewBag.RegisterClientsSript;
}
else
{
scripts = new Dictionary<string, string>();
helper.ViewBag.RegisterClientsSript = scripts;
}
if (!scripts.ContainsKey(key))
{
scripts.Add(key, script);
}
}
public static MvcHtmlString RegisterClientsSript(this HtmlHelper helper)
{
var outScripts = new StringBuilder();
if (helper.ViewBag.RegisterClientsSript != null)
{
var scripts = (Dictionary<string, string>)helper.ViewBag.RegisterClientsSript;
foreach (string script in scripts.Values)
{
outScripts.AppendLine(script);
}
}
return MvcHtmlString.Create(outScripts.ToString());
}
public static MvcHtmlString Paging(this HtmlHelper helper, string uniqId)
{
helper.AddRegisterClientsSript("jquerypaginatecss", #"<link href=""/Content/Paginate/jquery.paginate.css"" rel=""stylesheet"" />");
helper.AddRegisterClientsSript("jquerypaginatejs", #"<script src=""/Content/Paginate/jquery.paginate.js""></script>");
}
}
2- Add the namespace in page and use it
#using Mirak.Ui.Components
#section scripts{
#Html.RegisterClientsSript()
}

Resources