Routing issue when using URL.Action - javascript

All,
I have the following route/action defined on my controller :
[RoutePrefix("widgets/download-functions")]
[Route("download/{publishedReportId}"), HttpGet]
public ActionResult Download(int publishedReportId)
And inside my js code, I want to create some routing with the appropriate id.
This is what I have inside my js code (which doesn't work). What am I missing?
self.downloadFile = function (data) {
console.log(data);
console.log("#(Url.Action("Download", new { publishedReportId = 9999 }))");
console.log("#(Url.Action("Download"))");
};
Still new to this stuff and learning, I am sure it is something simple.
When I run this code, I get the following in the console
Console output
Thx
jonpfl

If you are using Url.Action, it doesn't take advantage of attribute routing, you will need to follow the original method of routing, which is to use, Action, Controller, area and params to get the extension method to produce the url.
[RoutePrefix("widgets/download-functions")]
public class WidgetDownloadController : Controller
...
[Route("download/{publishedReportId}"), HttpGet]
public ActionResult Download(int publishedReportId)
You would get a Url.Action like:
console.log("#(Url.Action("Download","WidgetDownload", new { publishedReportId = 9999 }))");
Also, this will only work on scripts that are parsed by the razor engine, ie. scripts that are written directly in the view.

Related

Passing Object from ASP.Net to javascript

I have an ASP.Net Core application. I have a Class with some attributes:
public class myClass
{
public string name {get; set;}
public int id{get; set;}
...
}
and in PageModel of Index.cshtml, I am creating on object of that class and setting it is a property:
public class IndexModel : PageModel
{
public myObj data { get; set; }
public void OnGet(int inputId)
{
data = new myClass();
data.name = "name";
data.id = inputId;
}
}
Now, in my Index.cshtml, I have some default html and then I add a script like this:
<script type="module" src="~/built/script.js"></script>
Finally, my question: I need the data that I have defined in IndexModel in my script.js. In a normal cshtml-page, I would do #Model.data, but that decorator is not available in my js file. Is there a way to do this, or should I use one of the following which I think might work:
Adding an API-controller in ASP.Net and calling it in my script.js with ajax: I think this should work, but it seems to me like I am supposed to do it with #Model instead
Somehow storing it in a global variable in my .cshtml file and then accessing that global variable in script.js: Seems like a hack
I'm pretty new to ASP.Net and JS, so there might be an obvious answer to this that I'm just too inexperienced to know. Any help is appreciated!
You could use model binding as intended and convert the model to a javascript variable at the top of your view, then it will be available in the script file as a javascript variable as long as you load the javascript file after you create the variable to hold your model.
---YOUR VIEW---
#model YourModel
#using Newtonsoft.Json;
<script type="text/javascript">
let mymodel = #Html.Raw(JsonConvert.SerializeObject(Model));
</script>
--Import your script file after creating javascript variable and mymodel should then be available
<script type="text/javascript" src=""></script>
--Use mymodel in your script file
There are four ways to do this, you found two of them. I'll give you the pro's and cons in order of complexity:
AJAX:
It's not that hard, use the "fetch" method built into the window object. But, it's asynchronous so you have to deal with callbacks in JavaScript, you will need to secure the API so it only accepts authorized clients (usually done with OAuth, but you could just inject an authorization code for the client JavaScript to use), and you need to identify yourself (like a session) to the API to get the right data so that is another code. Oh wait, we have to inject a code? So what's the point of using AJAX? True, only use AJAX when you need to dynamically get new data without reloading the page!
JavaScript injection:
You never want to inject into a .js file, they should be static and that's why you discovered it won't work. So you have to inject some JavaScript code creating variables into the page that is loading the JavaScript. That's what you proposed and that is completely fair to do. It's isn't a hack. It should be one variable with a JSON string.
Cookie:
Put the data into a temporary cookie delivered with the page and read the cookie from JavaScript. This is cleaner than the variable solution, but isn't the simplest way.
HTML injection:
There is one other possibility for using #Model, instead of injecting the JSON string into a JavaScript variable, which requires injecting JavaScript tags too, put it into a property on an HTML element and then access the property from JavaScript. This is simpler and my preferred method. Property names beginning with "data-" are designed for this.

Trying to access a model object inside a script tag

I'm using Asp.Net Core and trying to reference the model from inside a script tag:
<div>
<script>
function calcprices() {
#Model.Price = document.getElementById("price").value;
}
</script>
<button onclick="calcprices()">Recalculate</button>
The error showing in console window is:
ReferenceError: calcprices is not defined
If I have a look at the debugger, it shows the particular section is missing the Model reference:
function calcprices() {
= document.getElementById("price").value;
}
So I'm guessing that's why I'm getting an error. Is it not possible to reference a model like this?
It's not possible to reference your model that way. In Razor, the C# and #Model.x elements are executed as the page is run and outputs are rendered as plain text.
If your #model.Price had a value (say 10 for example) it would be rendered on screen like this:
function calcprices() {
10 = document.getElementById("price").value;
}
You can use them as static values in your javascript (something we've made extensive use of) but you cannot address them as objects.
I'd suggest, if you're trying to update an object in session, use ajax to call a JsonResult method, post your data and return the output in the Json result.

Call a Javascript form within a controller in MVC4

I want to call a javascript function from within a controller function that I use:
Public Function redirectTo() As JavaScriptResult
Return JavaScript("ToSignUp()")
End Function
in my controller. But the program never goes to the script. I've already checked similar answers but I haven't found any solution to the problem. Can someone assist me with this?
ADDITION 4/3/19 12:41
I use the following for redirection from my controller... but nothing is happening:
Public Function redirectTo() As RedirectToRouteResult
Dim routes As New RouteCollection With {.RouteExistingFiles = True}
Return RedirectToAction("../login/SignUp")
End Function
End Class
ADDITION 4/3/19 23:20
The issue was solved by this way
In the code behind of my .aspx Page and at the proper place I add it the following code:
Dim routes As New RouteCollection With {.RouteExistingFiles = True}
Response.Redirect("SignUp")
The Response.Redirect instruction is not new.
But in order to be functional it needs to add before the following instruction
Dim routes As New RouteCollection With {.RouteExistingFiles = True}
And that is because the MVC did not recognize the existent files which means the property RouteExistingFiles is always False
Thus in order to work the code we need to turn this property to True
Anyway thanks to all for your assistance.
From other examples online (like this one), I would say that if you temporarily changed your function to:
Public Function redirectTo() As JavaScriptResult
Return JavaScript("alert("HERE");")
End Function
It will likely work... so without seeing the JS function contents, it's hard to tell. To the second point, a RedirectToAction call will work if called from the server; if the client is calling this, use 'window.location' instead.

Take C# const from backend and use it in JS file?

I have one tricky question.
Is there a way to take C# const and use it in .JS script with Jquery ?
This is how const look:
public class UserRoles
{
public const string Read = "Read";
public const string ReadWrite = "ReadWrite";
}
It depends a bit of what you are trying to do with those values.
You could place the values in a js object when your UI initializes (ex: window.YourAppName.Constants.Read = "your C# constant" in Index.html). Then you could load your jquery script and make use of the constant values once the document finished loading.
Alternatively, if you are using MVC, you can make use of tags within your views, and thus have access to C# code (viewmodel, enums, etc.). However, if you have lots of js code then it would be best to keep that in js files and in such a case I would go for the first option.
You can't use Razor in JavaScript files, you would have to have the variable passed to a razor view in the viewbag/data or model.
Then in the shared layout you could create a javascript function that returns this variable, then in your .JS file you could call that function to get the variable as long as it is loaded after.

How to redirect to a play framework url from within javascript without hard-coding the url

I need to do something seemingly quite simple.
In the same way that I can, from my scala.html file, create a link to another url, /entry, I need to do that from a javascript file.
i.e., from the scala.html:
<div class="footer">
<a href='#routes.Application.index()'>Home</a>
</div>
from my javascript event:
function() myEvent {
window.location="#routes.Application.entry()"; // DOESN'T WORK!
}
For routing from javascript, I've already had to setup my javascript routes for some ajax work I've already had to do.
My ajax work was calling a method 'findPersons()' so in my Application.java file, I had already:
public Result jsRoutes()
{
response().setContentType("text/javascript");
return ok(Routes.javascriptRouter( "appRoutes",
routes.javascript.Application.findPersons()));
}
Because I want to be able to redirect to my GET entry() method, I modified it to look like this:
public Result jsRoutes()
{
response().setContentType("text/javascript");
return ok(Routes.javascriptRouter( "appRoutes",
routes.javascript.Application.findPersons(),
routes.javascript.Application.entry()));
}
Additionally I have these in my routes file:
GET /entry controllers.Application.entry()
POST /findPersons controllers.Application.findPersons()
When I am invoking my findPersons method, it is really nice and simple.
It looks like this:
appRoutes.controllers.Application.findPersons().ajax({
data: {
personIdentifier : personIdentifier,
surname : surname,
givenNames : givenNames
},
success : processDBQuery
});
For my simple redirect, I would like to be able to maintain the same loose coupling between my html/javascript code and the urls, as I can the ajax call above.
My redirect needs to occur on an event. Therefore, the easiest and quickest solution would have been simple to write:
function() myEvent {
window.location="/entry";
}
However, then I would be hard-coding the URL (which I have managed to avoid for my ajax call above), no longer maintaining that loose coupling I would so much like to have.
However, I see no examples in the documentation, and from what I have in the generated javascript (for my routes) there is no chance.
Is there any way to achieve what I am after?
thanks for reading!
p.s., I should add; I guess I have also thought of the possibility of using the ajax call that is generated, I guess I can probably fetch the page I want... and there is probably a means of replacing the current document with the entire content of the fetched page. but that just sounds bad.... wrong...
or not?
I was rather hoping for a substitution, as is done in my html
i.e, my link as shown above is generated to look like this:
<div class="footer">
<a href='/'>Home</a>
</div>
In the same way, I hoped there was some means of substitution in the javascript, so that the event function above ends up in being massaged into looking like this:
function() myEvent {
window.location="/entry";
}
Jacques, from the above comments, helped me to realize a work-around.
From within my "assets located" javascript file, I can still refer to page/template located javascript.
Own-file/assets located javascript doesn't seem to be transformed how I expected.
However, Page/template located javascript is transformed exactly how I require.
I can refer to a template located javascript function from my assets located javascript.
This means, I have a little work-around of one extra little function inside the template which does the redirection for me.
i.e.,
myJavascript.js:
function personResultsListClickHandler(personId) {
var fpersonId = personId;
return function() {
window.alert("hello! " + fpersonId);
affectRedirect();
};
}
myTemplate.scala.html
#main("person lookup") {
<script type="text/javascript">
function affectRedirect(){
window.location="#routes.Application.entry()";
} // Need this here so it will be transformed.
// asset located javascript doesn't seem to get transformed like javascript here in template! :(...
</script>
Another possibility is the fact that the Javascript object retrieved by calling:
appRoutes.controllers.Application.entry()
contains a url member. This url member is exactly what I can use to assign to window.location. However, it looks a bit unofficial.. in terms of
1. the member not being documented
2. not sure if the url member will exist in the future
3. the generated javascript is constructing an object dealing with ajax... and i'm just grabbing the URL member from it... it just feels... like a hack.
But i've tested this, and it works. See code below:
function patientResultsListClickHandler(personId) {
var fpersonId = personId;
return function() {
window.location=appRoutes.controllers.Application.entry(personId).url;
// window.location="/entry/" + fpersonId; // the sort of hard-coding of URL that
}; // I wanted to avoid, but don't seem able to.
}
Does anyone else have a better solution?

Categories

Resources