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

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.

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

MVC controller method not being triggered by jquery in the view

I have the following method in a controller called "ProductController":
public ActionResult LoadProducts(int prodID)
{
return View();
}
I'm trying to trigger it from a view cshtml page this way:
#section Scripts {
<script type="text/jscript">
$('#MyProducts').change(function () {
var selectedID = $(this).val();
$.get('/Product/LoadProducts/' + selectedID, function (data) {
window.alert(selectedID);
});
});
</script>
}
<div>
#using (Html.BeginForm("Update", "Product", FormMethod.Post, new
{ enctype = "multipart/form-data" }))
{
#Html.DropDownList("MyProducts",
(IEnumerable<SelectListItem>)ViewBag.MyProducts as
IEnumerable<SelectListItem>, "Select")
}
</div>
The call to the jquery works when I change the value in the drop down, as I tested it via the popup box, but getting it to trigger the action method in the controller is not working.
Thanks.
In your controller, you can use HttpGetArribute to define the route. Without specifying the route, the parameter is considered as optional and it should be called as Product/LoadProducts?prodId=1. Example of HttpGetAttribute:
[HttpGet("[controller]\[action]\{prodId}")]
public ActionResult LoadProducts(int prodID)
{
return View();
}
set Url by Url.Action
var Url='#(Url.Action("ActionName","ConttrolerName"))';
and Put the variable name of the sent with the same variable received
SelectedID to ProdID
<script type="text/jscript">
$('#MyProducts').on("change",function () {
var Url='#(Url.Action("LoadProducts","Product"))';
var SelectedProdID = $(this).find("option:selected").val();
$.get( Url,{prodID:SelectedProdID}, function (data) {
window.alert(selectedID);
});
});
</script>
Suggestion: use script type="text/javascript". I am not an expert on which browsers support "jscript" but after 20 years of development I can assure you all browsers support javascript.
Also, I would discourage you from using the code which Farhad Bagherlo posted. If at all possible you should avoid using razor code inside your script tag because you may want to move this code into separate JS files or later on refactor to use TypeScript. Also, why invoke a method on the server to get an endpoint/url if you already know the path which is needed. seems wasteful. However, you could use the method he outlined to ensure that you are actually giving the correct URL. If his code works then what is the value of "Url"? (also, the client side standard for naming variables is camelCase, so url should be lower.)
If you are debugging your code and set a breakpoint in your controller. then you should be able to get it to break on that line by simply navigating to that route.
If you go to http://localhost:post/Product/LoadProducts/1 does it actually break on that line in Visual Studio?
Edit: #Transcendent is correct and would get my vote, need to understand how routing is defined vs arguments/parameters passed to the action method. Nice call Transcendent!
I agree with Collin on that using razor in your javascript marries them and that can be a pain if you try to split the js into its own file. I recently had to go through it.
Edit: This is just to show how to use Url.Action and still be able to separate js into a separate file by the use of data property in the div
What I suggest is doing something like:
#section Scripts {
<script type="text/javascript">
$('#MyProducts').change(function () {
var url = $('#mydiv').data('url') + '?prodId=' + selectedID;
var selectedID = $(this).val();
$.get(url, function (data) {
window.alert(selectedID);
});
});
</script>
}
<div id="mydiv" data-url="#(Url.Action("ActionName","ConttrolerName"))">
#using (Html.BeginForm("Update", "Product", FormMethod.Post, new
{ enctype = "multipart/form-data" }))
{
#Html.DropDownList("MyProducts",
(IEnumerable<SelectListItem>)ViewBag.MyProducts as
IEnumerable<SelectListItem>, "Select")
}
</div>

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");

How to access section from extension method?

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;
}
}

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"));}

Categories

Resources