I am creating a web page using ASP.Net WebAPi, MVC and Knockout.
I have a normal MVC controller that loads the pages when I need them:
[Authorize]
public class AdminController : Controller
{
public ActionResult Clients()
{
return View();
}
public ActionResult ClientEdit(int? Id)
{
return View();
}
}
And once the page is loaded, my Knockout model takes care of the loading of the data. So, the 'Clients' controller simply loads a list of all clients. When on that screen, a user can click 'Edit' next to a client, and the page is navigated to the 'ClientEdit' controller, which takes an id.
So, my knockout click event looks like this in my knockout view model:
self.EditClick = function () {
if (this.ClientId && typeof this.ClientId !== 'undefined') {
window.location.href = "/Admin/ClientEdit/" + this.ClientId;
}
else
window.location.href = "/Admin/ClientEdit/";
}
(It handles the 'Create New' button and the edit button, hence the 'if')
Once I redirect, the MVC controller loads the page, and the URL is:
http://localhost:49389/Admin/ClientEdit/1
I then load the knockout model, and would like to make an API call to get the data...
After my page loads, I want to bind the view model to the page. Here's my view model at the moment:
function AdminClientEditor() {
var self = this;
self.Name = ko.observable("");
self.ContactName = ko.observable("");
ko.applyBindings(new AdminClientEditor(), $("#clienteditor")[0]);
So, I will create a $.get method that calls a webAPI method that will return me data based on the id. I just need to get the ID somehow.
But, how do I get the Id (In this case, '1', from the URL?
And, is this the right way to achieve what I am trying to do?
You can pass the id value to view via viewbag.
public ActionResult ClientEdit(int? Id)
{
ViewBag.ClientId=id;
return View();
}
and in the view's script section
var clientId="#ViewBag.ClientId";
alert(clientId);
// use this
If your javascript code which accesses this id value is inside a separate external js file, you may set this value to a js variable in your view and access it in your js file. Make sure to use namespacing to avoid global variable overwriting value issues.
So in your view
<script>
var myApp = myApp || {};
myApp.ClientId= "#ViewBag.ClientId";
</script>
<script src="~/Scripts/PageSpecificExternalJsFile.js"></script>
And in the PageSpecificExternalJsFile.js file,
var clientId=myApp.ClientId;
//use this as needed
I'm not sure if this is the best way, but you can get the ID from the URL by using JS:
var id = GetID();
function GetID() {
var href = location.href;
var results = href.split("/");
return results[results.length - 1];
}
I've come up with this solution which works, but I am unsure if it's the best way. It seems pretty good.
I created a MVC ViewModel class in my application code, called 'GenericParameteModel', which at the moment, has a single parameter, "Id".
I then modified my page loading MVC method:
public ActionResult ClientEdit(int? Id)
{
var mv = new GenericParameteModel { Id = Id };
return View(mv);
}
On my View page, I added the model 'GenericParameteModel' to the View.
I created a hidden field, called 'ClientId' on the view.
<input type="hidden" id="clientId" value="#model.Id">
Then, within my knockout view model, I check if $("#clientId").val() has a value. If so, I do the $.get call, using that value, and populate my view model.
In doing so, all my initial page loads from MVC will have the ability to you the GenericParameteModel, and it will be a pattern for other pages. As it's a model, I can add new fields as my application requires.
This seems to work well. I'm unsure if this is an acceptable way as I am new to this (MVC to load views and the Knockout/WebApi to get the data after loading). But it seems neat and manageable.
Related
Once again stumped on a partial view issue using ajax to swap out partial views.
I have a partial view that is loaded onto a page when the page is loaded. This partial view has a button on it that when clicked, will replace that partial view with another partial view. Previously I was accomplishing this with #Ajax.ActionLink and passing in the page's Model as a parameter to be passed to the controller. This was working correctly.
However, the next step was to fill in a form on the new partial view and submit it which would return another partial view. I asked how to do that on here and got it to work using jquery event delegation.
Now I'm trying to replace the #Ajax.ActionLink with a $.ajax function and am running into an issue with my js script where the model data already in the view or partial view is not being passed to the controller by the js.
Here's what I mean:
I have a page called ReviewPage that on load, will call an action that returns a partial view. This partial view is determined based on a value from the page's model that is passed to the controller. More often than not, the view returned is _NoNotes:
#model GuestPointerAppV4.Models.ViewModels.NotesOnCompanyViewModel
<div id="no_company_notes">
<h4>Notes on Company</h4>
<div class="row col-sm-6 col-sm-offset-6">
<div class="text-center">
#Html.HiddenFor(item => Model.RequestId)
<div class="primary-action-bttn-border">
<div class="primary-action-bttn-bkg">
<button data-gp-ajax="true" data-gp-target="#no_company_notes" value="Save" action="#Url.Action("_CompanyNotesEditGet", "NewSignUpRequestReview")" method="get" class="btn btn-default primary-action-bttn">
Add Note
</button>
#*#Ajax.ActionLink("Add Note", "_CompanyNotesEditGet", Model, new AjaxOptions { UpdateTargetId = "company_notes", InsertionMode = InsertionMode.Replace, HttpMethod = "GET" }, new { #class = "btn btn-default primary-action-bttn" })*#
</div>
</div>
</div>
</div>
<div class="row text-center padding-25-top">
<p>There are no notes for this company. Do you want to add some?</p>
</div>
</div>
You'll notice the commented out ajax action link in the code above. This was how I was previously able to get the model passed to the controller.
When the button is clicked on this partial view, the following js responds:
$(document).on('click', 'button[data-gp-ajax="true"]', function () {
var $form = $(this);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize()
};
$.ajax(options).done (function (data) {
var $target = $($form.attr("data-gp-target"));
$target.replaceWith(data);
});
return false;
});
I want to reuse this js as much as possible so I utilize custom data- attributes to help call the right function (data-gp-ajax="true") and tell the script where to return the results (data-gp-target="#targetid").
The problem is that in debugging this, I found that while Model.RequestId is not 0 on the page, this value is not getting picked up by the js and passed to the controller. So, when my controller looks for the data it doesn't find it and returns a null or 0 depending on the type of data I'm trying to pass.
I did a bit of research and tried to encode the Model in the partial view itself using the following at the top of the partial view's code just after the model typing:
#{
var val = Json.Encode(Model);
}
<script type="text/javascript">
var model1 = #Html.Raw(val)
</script>
Then, in my js function, I tried passing model1 to the controller by using it like so:
$(document).on('click', 'button[data-gp-ajax="true"]', function () {
var $form = $(this);
var $model = $(model1);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $model.serialize()
};
$.ajax(options).done (function (data) {
var $target = $($form.attr("data-gp-target"));
$target.replaceWith(data);
});
return false;
});
I also tried data: $model and data: $model.first() but no such luck. I managed to debug and see the data I was expecting to see in the js on the $model variable so I know it's getting in there but it isn't getting passed to my controller when it's called.
Really what I'm looking for is a clean and reliable way way to pass the Model for the page into the JavaScript and have it pass it along to the Controller to execute some action on before a partial view is returned to replace the original partial view.
Thoughts?
Update
Here is an example of the controller:
[HttpGet]
public ActionResult _CompanyNotesEditGet(NotesOnCompanyViewModel notesOnCompanyViewModel)
{
//Some actions are taken on the model passed in and then repopulated to notesOnCompanyViewModel
return PartialView("~/Views/NotesOnCompany/_CompanyNotesEdit.cshtml", notesOnCompanyViewModel);
}
However, when I debug and the action is called by $.ajax, the notesOnCompanyViewModel is blank. Even when I can see there is data that should be getting passed by the js function.
All you need is to send the unique Id. for that, you can simply override the button click event and make an ajax call with the Id in the request url. If you would like to take advantage of the Url helper method to generate the correct relative path to the action method, you can do that and set the result of that to html5 data attribute on the button.
<button id="addNote"
data-url="#Url.Action("_CompanyNotesEditGet", "NewSignUpRequestReview",
new { id=Model.RequestId})" >
Add Note
</button>
Assuming your _CompanyNotesEditGet action method accepts this Id and return the value as needed
public ActionResult _CompanyNotesEditGet(int id)
{
var vm= new NotesOnCompanyViewModel { RequestId=id };
//load other properties of vm as needed.
return PartialView(""~/Views/NotesOnCompany/_CompanyNotesEdit.cshtml",vm);
}
And the script to ajaxify the click event. You can use the load method to make the ajax call and update the DOM element.
$(function(){
$(document).on("click","#addNote",function(e){
e.preventDefault();
var url=$(this).data("url");
$("#no_company_notes").load(url);
});
});
If you are editing a note, Inside your action method, you can read your note entity from the db using the Id passed in.
This should work assuming you have no script errors in the page.
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¶meter1=test¶meter2=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");
Coming from a webform background using ajax I am trying to create similar with mvc.
I have worked out what the controller, view and models do.
What i would like to do now is that when my user clicks a button an jquery call is made to update the view - hence not refreshing the entire page.
Much like a master/child design in webforms.
I have googled and I have tried a couple of things but I get a 404. I have checked and i am sure I am calling things correctly.
This is my jquery function:
$("#divProductsBanner").click(function () {
var currentObject = $(this).text();
$.get('#Url.Action("Lite", "Service")', { theName: currentObject });
});
Where 'Lite' is my view and 'Service' is my controller.
my Service.cs controller looks like this:
public ActionResult Lite()
{
return View();
}
and I have a view called 'Lite' under my 'Service' folder under the 'Views' folder.
when I click that button i get this error:
You can not use C# code in JS file. You can render the URL in the hidden field and use it
Something like
#Html.Hidden("MyURL", #Url.Action("Lite", "Service"))
In js
$("#divProductsBanner").click(function () {
var currentObject = $(this).text();
$.get($("#MyURL").val(), { theName: currentObject });
});
Refer the links and change your code accordingly.
Asp.Net Mvc Url.Action in external js file?
Use Seprate js File And use Url Helpers in it with ASP.NEt MVC 3 and Razor View Engine
Hi I am new to MVC and I have the below senario
VIEW:
step3.cshtml is my view
This has data binded to step3.js(using knockout)
$.post("/Step/Step4", { "some":some_data }, function (data) {
}, 'JSON');
CONTROLLER:
[HttpPost]
public ActionResult Step4(model foo)
{
//save this data to the database and return a view
using (DBContext dbContext = new DBContext())
{
dbContext.Table.Add(foo);
dbContext.SaveChanges();
}
return View(foo);
}
public ActionResult Step4()
{
//get this view with the model
}
I am able to see that the view Step4.cshtml is able get the property values from model but.
I see that my View Step4.cshtml is a response header from the post how do I render this in the browser.
Is this the right approach??
So is it that an HTML form post can return a view and replace the whole content and AJAX cannot do that except for the partial view update?
When you call $.post, you are making a jQuery ajax request with a POST method. That data is given back to you in the success method. If you are returning the view, then you will have to manually replace the html in your document with that response.
Normally, when you use ajax like this, you would return a PartialView to update a section of your page, not your whole page. You might want to see if you can return a partial and update a div.
You can also do that by using an Ajax.ActionLink, and in the AjaxOptions, specify the id of the element you want to update when the response is returned, and the InsertionMode, which should be set to Replace. And you won't have to worry about replacing the content yourself.
Please see this stackoverflow question, which may help you: How To Use Ajax.ActionLink
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.