How to access section from extension method? - javascript

I'm writing html extension (Razor) for javascript rendered charts.
I can edit javascript to read most values from data attributes, but sometime I need to insert directly inline javascript into the page and link a library. I want to make it automatic.
Is there some way to access a section (like #RenderSection("Scripts", false) ) from extension method via html helper?
Thank you

RenderSection is regular method of WebPageBase so you can use it in your helper. Here you have a snippet:
public static class HtmlExtensions
{
public static HelperResult InvokeRenderSection(this HtmlHelper html)
{
var view = (WebPageBase)html.ViewDataContainer;
var result = view.RenderSection("scripts", false);
return result;
}
}

Related

Access RESX file from external javascript file [duplicate]

How would one get resx resource strings into javascript code stored in a .js file?
If your javascript is in a script block in the markup, you can use this syntax:
<%$Resources:Resource, FieldName %>
and it will parse the resource value in as it renders the page... Unfortunately, that will only be parsed if the javascript appears in the body of the page. In an external .js file referenced in a <script> tag, those server tags obviously never get parsed.
I don't want to have to write a ScriptService to return those resources or anything like that, since they don't change after the page is rendered so it's a waste to have something that active.
One possibility could be to write an ashx handler and point the <script> tags to that, but I'm still not sure how I would read in the .js files and parse any server tags like that before streaming the text to the client. Is there a line of code I can run that will do that task similarly to the ASP.NET parser?
Or does anyone have any other suggestions?
Here is my solution for now. I am sure I will need to make it more versatile in the future... but so far this is good.
using System.Collections;
using System.Linq;
using System.Resources;
using System.Web.Mvc;
using System.Web.Script.Serialization;
public class ResourcesController : Controller
{
private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();
public ActionResult GetResourcesJavaScript(string resxFileName)
{
var resourceDictionary = new ResXResourceReader(Server.MapPath("~/App_GlobalResources/" + resxFileName + ".resx"))
.Cast<DictionaryEntry>()
.ToDictionary(entry => entry.Key.ToString(), entry => entry.Value.ToString());
var json = Serializer.Serialize(resourceDictionary);
var javaScript = string.Format("window.Resources = window.Resources || {{}}; window.Resources.{0} = {1};", resxFileName, json);
return JavaScript(javaScript);
}
}
// In the RegisterRoutes method in Global.asax:
routes.MapRoute("Resources", "resources/{resxFileName}.js", new { controller = "Resources", action = "GetResourcesJavaScript" });
So I can do
<script src="/resources/Foo.js"></script>
and then my scripts can reference e.g. window.Resources.Foo.Bar and get a string.
There's no native support for this.
I built a JavaScriptResourceHandler a while ago that can serve Serverside resources into the client page via objects where each property on the object represents a localization resource id and its value. You can check this out and download it from this blog post:
http://www.west-wind.com/Weblog/posts/698097.aspx
I've been using this extensively in a number of apps and it works well. The main win on this is that you can localize your resources in one place (Resx or in my case a custom ResourceProvider using a database) rather than having to have multiple localization schemes.
whereas "Common" is the name of the resource file and Msg1 is the fieldname. This also works for culture changes.
Partial Javascript...:
messages:
{
<%=txtRequiredField.UniqueID %>:{
required: "<%=Resources.Common.Msg1 %>",
maxlength: "Only 50 character allowed in required field."
}
}
In a nutshell, make ASP.NET serve javascript rather than HTML for a specific page. Cleanest if done as a custom IHttpHandler, but in a pinch a page will do, just remember to:
1) Clear out all the ASP.NET stuff and make it look like a JS file.
2) Set the content-type to "text/javascript" in the codebehind.
Once you have a script like this setup, you can then create a client-side copy of your resources that other client-side scripts can reference from your app.
If you have your resources in a separate assembly you can use the ResourceSet instead of the filename. Building on #Domenics great answer:
public class ResourcesController : Controller
{
private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();
public ActionResult GetResourcesJavaScript()
{
// This avoids the file path dependency.
ResourceSet resourceSet = MyResource.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
// Create dictionary.
var resourceDictionary = resourceSet
.Cast<DictionaryEntry>()
.ToDictionary(entry => entry.Key.ToString(), entry => entry.Value.ToString());
var json = Serializer.Serialize(resourceDictionary);
var javaScript = string.Format("window.Resources = window.Resources || {{}}; window.Resources.resources = {1};", json);
return JavaScript(javaScript);
}
}
The downside is that this will not enable more than one resource-file per action. In that way #Domenics answer is more generic and reusable.
You may also consider using OutputCache, since the resource won't change a lot between requests.
[OutputCache(Duration = 3600, Location = OutputCacheLocation.ServerAndClient)]
public ActionResult GetResourcesJavaScript()
{
// Logic here...
}
http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/improving-performance-with-output-caching-cs
I usually pass the resource string as a parameter to whatever javascript function I'm calling, that way I can continue to use the expression syntax in the HTML.
I the brown field application I'm working on we have an xslt that transforms the resx file into a javascript file as part of the build process. This works well since this is a web application. I'm not sure if the original question is a web application.
use a hidden field to hold the resource string value and then access the field value in javascript
for example :
" />
var todayString= $("input[name=TodayString][type=hidden]").val();
Add the function in the BasePage class:
protected string GetLanguageText(string _key)
{
System.Resources.ResourceManager _resourceTemp = new System.Resources.ResourceManager("Resources.Language", System.Reflection.Assembly.Load("App_GlobalResources"));
return _resourceTemp.GetString(_key);
}
Javascript:
var _resurceValue = "<%=GetLanguageText("UserName")%>";
or direct use:
var _resurceValue = "<%= Resources.Language.UserName %>";
Note:
The Language is my resouce name. Exam: Language.resx and Language.en-US.resx

asp.net mvc passing any data from a partial view that is rendered with $.get() to ContentPage

I am trying to make my web application like a desktop application.
I am also not using any _LayoutPage and #RenderBody().
I have a ContentPage as MasterPage and a tag named main
I am using ajax get method to render my views or partial views like this:
$.get(url).done(function (result) {
$("main").html(result);
});
I managed to inject my script and css files with javascript functions.
And now I want to pass some specific datas without using javascript functions.
It can be via using ViewBag, I guess.
I want to pass that data from my partialView:
ViewBag.BodyClass = "signup-page";
to my MainPage like this:
<body class="#ViewBag.BodyClass">
How can I do that?
A little note: Please ignore that I am a newbie and my low reputation
If you have a script manager ($.get) that calls your server to get the views and partial views, no problem.
When you request a URL, normally MVC calls a Controller and Action. In that action you can return content, view, partial view, file and so on...
You can create a new instance of a class model and pass to your partial view.
public ActionResult Index(string parameter1, string parameter2)
{
var model = new Models.ModelTest();
model.BodyClass = "some class";
return PartialView("_Page", model);
}
You will call some like this:
$.get("http://localhost/app/getviews?id=3422&parameter1=test&parameter2=foo")
In your view or partial view:
#model YourApp.Models.ModelTest
<body class="#Model.BodyClass">
I use that all the time.
I wrote that code on my partialView. It adds a class at ContentPage's body tag
$("body").addClass("signup-page");

Injecting javascript before PartialViewResult script is executed in EXT.NET?

I have a partial view which is requested & loaded into a modal window.
Following is the action method which generates the partial view:
public Ext.Net.MVC.PartialViewResult GetPartialView()
{
var p = new Ext.Net.MVC.PartialViewResult { Model = ...., ViewName = "MyPartialView" };
//!!need to manipulate p here to run my custom javascript on client!!
return p;
}
After GetPartialView() is called via ajax request, necessary scripts are generated and sent back to the client.
The executing script looks like this:
{script:"Ext.net.ResourceMgr.registerIcon([\"TextListBullets\",\"Add\"]);Ext.onReady(function(){Ext.create(\"Ext.window.Window\",{height:400,hidden..... bla bla}
Question:
How can i inject my own custom code somewhere in this generated javascript block?
My purpose is to dynamically load some external javascript files which are needed in the partial view.
I dont want to statically include script references in every main view i use this partial view. I want to gain some kind of automatization by loading js files when they are needed.
I'm sharing the answer from Ext.NET forum:
Please see the following sample
http://mvc.ext.net/#/Dynamic_Partial_Rendering/Add_Tab/
#{ MvcResourceManager.RegisterGlobalStyle(Url.Content("~/Areas/Dynamic_Partial_Rendering/Content/Tab.css"));}

Call an action from JS file instead of the view (MVC 4)

I'm using the MVC 4.
In my view i can simply get an action's url by using the: #Url.Action
Now i wanted to make a javascript file with all the view's javascript instead of writing it all in the view, the problem is i can't use the razor's stuff anymore.
so my question is how can i get the action's url from a javascript separated file?
You'll need to define a JavaScript variable within your view that you can then use in your script. Obviously this must be declared first.
I use a helper on my layout pages that has all these variables and a section for any I'd want specific to a page. Note these would come before any other script references before the body tag.
#Scripts.Variables()
#RenderSection("ScriptVariables", false)
The Scripts.Variables is something like this
#helper Variables()
{
<script language="javascript" type="text/javascript">
var ActionGetallAdmin = '#Url.Action("GetAll", "Admin")';
var ActionAccountLogin = '#Url.Action("Login", "Account")';
</script>
}
One way I did this before was to create views that served JS files (and CSS files, actually), instead of HTML files. This leverages the fact that views aren't necessarily HTML files all the time in the MVC paradigm.
You could do this by creating a controller for it:
public class AssetController : Controller {
protected void SetMIME(string mimeType) {
// implementation largely removed
this.Response.Headers["Content-Type"] = mimeType;
this.Response.ContentType = mimeType;
}
// this will render a view as a Javascript file
public void ActionResult MyJavascript() {
this.SetMIME("text/javascript");
return View();
}
}
Once you've done that, you can create a view (using the way you normally do it in ASP.NET MVC), and just write it up as Javascript. Remember not to use a layout, as you obviously don't want that.
Everything that views in MVC has to offer is available to you, so feel free to use models, et al.
#model IList<Entity>
#{
Layout = null;
}
(function ($) {
// javascript!
#foreach(var entity in Model) {
$('##entity.Id').on('click', function () {
console.log('#entity.Name');
});
}
})(jQuery);
Then you can wire that up using old-fashioned Razor in your other views.
<script src="#Url.Action("MyJavascript","Asset")"></script>
Which will roll out something like
<script src="http://your.domain/asset/myjavascript"></script>
Works like a charm. The views are dynamically created, of course, so be wary if you're nit-picky about that. However, since they are MVC controller actions and views, you can set cache options on them just as with any other view.
Uhm... I think you can define a special route, like "actionsjs", that points to an action.
routes.MapRoute(name: "actionsJs",
url: "actionsjs",
defaults: new { controller = "Home", action = "GetActions" });
In the action you've to set the content to the right type:
Response.ContentType = "text/javascript";
Then you'll return a specific View that will contains javascript code with some Razor inside.
#{
Layout = "";
}
$(function() {
var a = #(1 + 2);
});
At this point you'll able to add this "script file" to your site:
<script type="text/javascript" scr="#Url.Action("GetActions", "Home")"></script>
Should work.
If you want the root path, use a variable on layout and use that in JavaScript file, say
// In layout view
<script>
var rootPath = #Url.Content("~/")
</script>
User rootPath anywhere in your application JavaScript files
If you want to get full path of a controller with action then
// View
<script>
var url = #Url.Content("ActionName", "ControllerName")
</script>
use url in your JavaScript file.

ASP.Net MVC Upload file using jquery-form plugin and returning a Json result

I'm trying to use the JQuery Form plugin (http://jquery.malsup.com/form/) to upload a file and a couple extra fields from my view, and I want the action method to return a Json result to the javascript callback.
Currently, the ActionMethod is called correctly (I can process the files and fields from the form) but when I return the Json result the browser tries to download it as a file (If I download the file and see its contents, it's the JSON content that I am returning.).
This is my form:
<form id="FormNewFile" action="#Url.Content("~/Home/AddFile")" method="post" enctype="multipart/form-data">
<input type="hidden" name="eventId" value="25" />
<input type="text" name="description" />
<input type="file" name="fileName" />
<input type="submit" value="Send!" />
</form>
This is my javascript:
<script type="text/javascript">
$(function () {
$("#FormNewFile").ajaxForm({
dataType:'json',
success:processJson
});
});
function processJson(a,b) {
alert('success');
}
</script>
And this is my ActionMethod:
[HttpPost]
public ActionResult AddFile(long? eventId, string description)
{
int id = 5;
return Json(new {id});
}
The name of the file the browser tries to download is something like AddFilee87ce48e, with the last 8 characters being random hexadecimal characters.
And finally, the content of the file downloaded is:
{"id":5}
And the processJson function in javascript never gets called.
I googled a lot and the only thing that seems to work is returning the JSON result as a "Content" result from the action method, I think that's the approach I'm gonna take, but I still want to know why this isn't working?
Any ideas?
What I ended up doing was manually serializing the object I wanted to return as JSON, if I do this then the response won't have a header, therefore it will be handled by javascript instead of the browser. I used this helper method:
public static ActionResult JsonPlain(object x)
{
var result = new ContentResult();
result.Content = new JavaScriptSerializer().Serialize(x);
return result;
}
Hope this helps someone else
That's normal behavior. Excerpt from the documentation:
Since it is not possible to upload
files using the browser's
XMLHttpRequest object, the Form Plugin
uses a hidden iframe element to help
with the task. This is a common
technique, but it has inherent
limitations. The iframe element is
used as the target of the form's
submit operation which means that the
server response is written to the
iframe. This is fine if the response
type is HTML or XML, but doesn't work
as well if the response type is script
or JSON, both of which often contain
characters that need to be repesented
using entity references when found in
HTML markup.
To account for the challenges of
script and JSON responses, the Form
Plugin allows these responses to be
embedded in a textarea element and it
is recommended that you do so for
these response types when used in
conjuction with file uploads. Please
note, however, that if there is no
file input in the form then the
request uses normal XHR to submit the
form (not an iframe). This puts the
burden on your server code to know
when to use a textarea and when not
to. If you like, you can use the
iframe option of the plugin to force
it to always use an iframe mode and
then your server can always embed the
response in a textarea. The following
response shows how a script should be
returned from the server:
This means that if you want to return JSON you need to wrap it in a <textarea> tags on your server. To achieve this you could write a custom action result deriving from JsonResult and wrapping the generated JSON inside those tags.
The following blog post, jQuery File Upload in ASP.NET MVC without using Flash, addresses the issue of wrapping the response in a textarea as described by Darin Dimitrov's answer.
Have a look at the action on your form tag:
action="#Url.Content("~/Home/AddFile")"
The only usage I've seen of this is in script tags such as :
<script language="javascript" src="<%=Url.Content("~/Scripts/jquery-1.3.2.js")%>
The correct reference for the action would be:
action="/Home/Addfile"
While I am not too sure about the explanation as to why but the UrlHelper:
Url.Content("~/somepath")
converts a virtual path to a absolute path and expects a physical file such as a javascript.
The json result might be being returned as a file download because the mvc framework is expecting a file download of some description. Just as:
<a href="<%= Url.Content("~/_docs/folder/folder/document.pdf") %>">
document.pdf</a>
would download or display a physical pdf file.
My solution using json and no specific javascript:
/// <summary>
/// A result to use in combination with jquery.ajax.form when we want to upload a file using ajax
/// </summary>
public class FileJsonResult : JsonResult
{
public JsonResult Result { get; set; }
public FileJsonResult(JsonResult result):base()
{
this.Result = result;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Write("<textarea>");
this.Result.ExecuteResult(context);
context.HttpContext.Response.Write("</textarea>");
context.HttpContext.Response.ContentType = "text/html";
}
}

Categories

Resources