Here's the situation: I have a Razor-generated list of items (that needs to stay Razor-generated):
#model MG.ViewModels.Profile.ProfileDetailsViewModel
foreach (var interest in Model.Interests)
{
<span class="subject-title">#interest.SubjectName</span>
<a data-bind='click: function(){viewDescription(#Html.Raw(Json.Encode(interest)))}'class="subject-description-button" href="#" title="View Details">details</a>
}
Users can update the details of each item by clicking a 'Details' link that encodes the Model for the viewDescription javascript function:
self.viewDescription = function (data) {
// pull data into KO observables
self.selectedInterestDescription(data.Description);
self.selectedInterestSubject(data.SubjectName);
self.selectedInterestId(data.InterestId);
self.triggerModal(true);
};
Within the modal that gets triggered, the user can send an AJAX request to an endpoint that updates the description. This much is working as I'd expect.
What I'm struggling with is - when the user is done updating, the razor Model still has the old data. So when the user clicks 'details' from the Razor-generated list after updating, the old #model data is encoded. How can I push the updated data to the #Model from javascript?
How can I push the updated data to the #Model from javascript?
You absolutely cannot modify anything on the server from javascript. All you can do is an AJAX request to the server which will return refreshed data to the client. Remember that once the view is initially rendered there's no longer any notion of #Model on the client. So talking about updating something that doesn't exist hardly makes any sense. After your AJAX request succeeds simply update the corresponding portions of your DOM that need to be updated. The controller action that you are hitting with AJAX could return all the necessary information for that.
Related
Our users asked to have the Kendo Tree show up in the MVC web app in a panel on the left hand side of the page. They want that left hand panel to be present on every screen.
Currently I have a section of my _Layout.cshtml page that renders the Kendo Tree:
<div>
#{Html.RenderAction("GetTree", "Tree");}
</div>
Inside that Action I make a database call to get the contents of the tree and bind the model to the view as follows:
#model IEnumerable<TreeViewItemModel>
But obviously with this pattern every page I go to the _Layout gets called and the tree data is fetched from the database again. This is not very efficient.
What is a better way so that I only make a single database call?
I'm going to assume that the content of the tree is the same for every page and every user.
In that case, you can cache the retrieved database data so that you don't have to retrieve it on every page render. There are lots of ways to cache it: the simplest is probably to use ASP.NET's own caching, which is described in detail (with walkthroughs) here.
You probably will still have to render it on every page (unless you want to get into partial page caching, and I'm not sure how that works in MVC) but you definitely can avoid the repeated database hit.
ETA: You can create a wrapper or helper class that retrieves the necessary tree data by company. The relevant method would look a bit like this:
public IEnumerable<TreeViewItemModel> GetCachedTreeDataByCompany(int companyId)
{
var data = Cache["TreeData"] as IEnumerable<TreeViewItemModel>;
if(data == null)
{
data = GetTreeData(); // whatever you need to do to get the data
Cache.Insert("TreeData", data);
}
return data.Where(tvim => tvim.CompanyId == companyId).ToArray();
}
I'd like some advice on this issue. Basically, I have 2 pages (for simplicity sake), and the second page is completely dependent on the first page.
So lets say the main page is a search page, and the second page is a view page.
The site works off XML requests, and the ultimate aim is to keep the XML requests to a minimum as each request is a little slow. I considered using Sessions, but I've had some problems in the past with sessions being mixed between users randomly which i only manage to curb by changing the recycle process in IIS to a very small time frame, so I'm wondering if there is any other way. I've tried TempData, but that expires after one request, so a page refresh on the view page doesn't seem possible. (or is it?)
Anyways, we have the Search page that has, say, 5 attributes that are required by the View page, but only 2 are needed to make the XML request on the view page.
e.g.
Search Page Contains:
ID,
Name,
City,
Email,
Height
View Page needs the following from the Search page to complete the xml request:
ID,
Name,
Email
View Page displays all the information from the search page, plus everything in the XML response.
The link i have in the search page only has the ID in the url, so name and email are required for the XML request on the second page some how. Not sure if it's possible without sessions?
What i've tried is:
Store the search results in TempData. That way, when someone clicks the 'View' link (View), the View page loads the search results like so:
var viewPage = SearchResults.Where(w => w.ID == id).FirstOrDefault();
The ViewModel then renders the page by grabbing the Name and Email from viewPage, making an XML request, and displaying the response, along with other required details from viewPage.
It works as expected with tempdata. Data only persists on the first request, dies on a page refresh. Sessions is the alternative, but is there any other?
(sorry for the wall of text :)
Why not using more standard techniques like a <form> tag in the search page pointing to the controller action that will perform the search:
#using (Html.BeginForm("search", "somecontroller", FormMethod.Get))
{
... some input fields for your search criteria
<button type="submit">Search</button>
}
and then you will have the Search controller action:
public ActionResult Search(SearchModel model)
{
var results = ....
return View(results);
}
I've used GET method on the form which allows the user to bookmark the results page and come back to it later.
I have a ASP.NET MVC application which has a view populated with a model which needs to retrieve some data from the user. Besides that, I also have a hidden div tag which contains more information but it should be visible only after the model was sent to the controller on a POST request and after it has processed the information from the model it should change the div tag to visible. Is some way to signal the view that the request was processed and render visible the div tag, remaining on the same page. I believe this is similar to a partial postback from ASP.NET.
Thanks,
Tamash
Yes that's possible via some AJAX functionality. I'm using jQuery in my example:
$.post('Controller/Action', $('#formId').serialize(), function() {
$('#yourDiv').show();
});
This uses jQuery to post the data contained in a form with the HTML id 'formId' to a URL 'Contoller/Action' and shows the div with id 'yourDiv' in case the AJAX request finished successfully. The call $('#formId').serialize encodes the form elements in HTML form with id formId for submission in the AJAX request.
More on jQuery and AJAX here
I have a dropdown list on my master page that needs to postback after being changed. After the postback, whatever page initiated the postback needs to be re-displayed.
My question is where do I handle this? Obviously I do not want to have to modify every Action in my project... My guess is to maybe postback to some other fixed action and have that action redirect back to the page that is the referrer. Am I correct? Any thoughts?
Thanks.
Jason
In Site.Master, I ended up wrapping the dropdown within its own form that posted back to a dedicated controller/action.
<% Using Html.BeginForm("ChangeRole", "Home")%>
<div id="roleSelector">Change Role: <%=Html.DropDownList("Role", DirectCast(ViewData.Item("Roles"), SelectList), New With {.onchange = "this.form.submit();"})%></div>
<% End Using%>
In the controller I used the following code to change the mode and then redirected back to the referring URL.
<AcceptVerbs(HttpVerbs.Post)> _
Public Function ChangeRole() As ActionResult
Me.CurrentUser.SetRole(DirectCast([Enum].Parse(GetType(Models.ApplicationRoles), Me.Request.Item("Role")), Models.ApplicationRoles))
Return Redirect(Request.UrlReferrer.ToString())
End Function
I am unsure if this is the recommended way but I have been unable to think of another solution.
When you post back from the dropdown list change what are you doing? Can you maybe handle this in a jQuery call thus eliminating the need to re-display the page at all?
Calls to Action Methods can be asynchronous as griegs says, as such, you can post whatever information you need from the radio buttons to an action method without needing to reload the page.
If you need to update a part of the page, you can replace it with the contents of a rendered action method. If you use the jQuery ajax methods, you can post specific information to your methods.
For example, something like this:
$(document).ready(function()
{
$("#myRadioButton").change(function()
{
//Post to your action method, with the value of the radio button, function to call on success
$.post('yourActionMethodUrl', $(this).val(), function()
{
//Update some part of the page
});
});
});
This is based on memory, so you may need to check the syntax.
I have an AJAX form that I am creating in my MVC project. If the form is submitted using normal browser function and a page refresh occurs I get validation information rendered in the form (the built in MVC validation based on ViewData.ModelState).
Is there a similiar validation mechanism for AJAX forms?
<% using (Ajax.BeginForm("Create", "GraphAdministration", new AjaxOptions()
{
OnSuccess = "newGraphSuccess",
OnFailure = "newGraphFailure",
HttpMethod = "POST"
}))
{ %>
<!-- some form stuff in here !-->
<% } //end form %>
It really depends on where you are getting the content from to display once the form has been posted. The Validation summary is performed created on the server so that is where you have to do the work.
As an example I was using some partial content in an .ascx file to render a form. You get the form in the page the first time round by calling the action directly with Html.RenderAction
You would have your Ajax.BeginForm etc. in the .ascx file. Then call it directly in an action.
When the Ajax call is made from the browser you get it to post to the same action. That way you can do all of the server side validation that you would normally. You should set up the Ajax call to replace the original form with the new html that is returned by the action.
One thing that you have to be aware of is that the replace JavaScript will replace the content of an element not the element itself so remember to us the id of a surrounding element.
Apologies if that is a little convoluted, if you want more details just comment and I'll flesh out the relevant bits.
Extra Detail:
All of this assumes that you are doing all of the validation on the server.
You are going to have a View that has all of the page stuff in it and then some partial content in a .ascx file, this is where your ajax form lives, it needs to be set to replace content by id. Its easiest if it has the same name as the action your ajax is going to call.
You can use Html.RenderAction to get it into the View. You can also pass in data with other versions of the same method. Your essentially calling it in the same way your ajax code will.
You will need to wrap it all in a div with an id set. Use this id in the partial as the content to replace.
When you render the page the html for the form and all of the ajax stuff will get put in.
When the ajax action is called the partial content will be returned with any validation performed. It will replace the content of the div that you gave the id to.
You can have different versions of the action by using [AcceptVerbs(HttpVerbs.Get)] and [AcceptVerbs(HttpVerbs.Post)] attributes
The main problem with this method is that its not self contained, the div with the id is external to the partial.