I'm still quite new to ASP.NET MVC and wonder how-to achieve the following:
On a normal view as part of my master page, I create a varying number of partial views with a loop, each representing an item the user should be able to vote for. After clicking the vote-button, the rating shall be submitted to the database and afterwards, the particular partial view which the user clicked shall be replaced by the same view, with some visual properties changed. What is the best practice to achieve this?
Here's how I started:
1. I defined the partial view with an if-sentence, distinguishing between the visual appearance, depending on a flag in the particular viewmodel. Hence, if the flag is positive, voting controls are displayed, if it's negative, they're not.
I assigned a Url.Action(..) to the voting buttons which trigger a controller method. In this method, the new rating is added to the database.
In the controller method, I return the PartialView with the updated ViewModel. UNFORTUNATELY, the whole view get's replaced, not only the partial view.
Any suggestions how-to solve this particular problem or how-to achieve the whole thing would be highly appreciated.
Thanks very much,
Chris
Trivial (but by all means correct and usable) solution to your problem is Ajax.BeginForm() helper for voting. This way you change your voting to ajax calls, and you can easily specify, that the result returned by this call (from your voting action, which will return partial view with only 1 changed item) will be used to replace old content (for example one particular div containing old item before voting).
Update - 11/30/2016
For example:
#using (Ajax.BeginForm("SomeAction", "SomeController", new { someRouteParam = Model.Foo }, new AjaxOptions { UpdateTargetId = "SomeHtmlElementId", HttpMethod = "Post" }))
ASP.NET MVC is a perfect framework for this kind of needs. What I would do if I were in your possition is to work with JQuery Ajax API.
Following blog post should give you a hint on what you can do with PartialViews, JQuery and Ajax calls to the server :
http://www.tugberkugurlu.com/archive/working-with-jquery-ajax-api-on-asp-net-mvc-3-0-power-of-json-jquery-and-asp-net-mvc-partial-views
UPDATE
It has been asked to put a brief intro so here it is.
The following code is your action method :
[HttpPost]
public ActionResult toogleIsDone(int itemId) {
//Getting the item according to itemId param
var model = _entities.ToDoTBs.FirstOrDefault(x => x.ToDoItemID == itemId);
//toggling the IsDone property
model.IsDone = !model.IsDone;
//Making the change on the db and saving
ObjectStateEntry osmEntry = _entities.ObjectStateManager.GetObjectStateEntry(model);
osmEntry.ChangeState(EntityState.Modified);
_entities.SaveChanges();
var updatedModel = _entities.ToDoTBs;
//returning the new template as json result
return Json(new { data = this.RenderPartialViewToString("_ToDoDBListPartial", updatedModel) });
}
RenderPartialViewToString is an extension method for controller. You
need to use Nuget here to bring down a very small package called
TugberkUg.MVC which will have a Controller extension for us to convert
partial views to string inside the controller.
Then here is a brief info on how you can call it with JQuery :
var itemId = element.attr("data-tododb-itemid");
var d = "itemId=" + itemId;
var actionURL = '#Url.Action("toogleIsDone", "ToDo")';
$("#ajax-progress-dialog").dialog("open");
$.ajax({
type: "POST",
url: actionURL,
data: d,
success: function (r) {
$("#to-do-db-list-container").html(r.data);
},
complete: function () {
$("#ajax-progress-dialog").dialog("close");
$(".isDone").bind("click", function (event) {
toggleIsDone(event, $(this));
});
},
error: function (req, status, error) {
//do what you need to do here if an error occurs
$("#ajax-progress-dialog").dialog("close");
}
});
There needs to be some extra steps to be taken. So look at the blog post which has the complete walkthrough.
Related
I edited my codes
.factory('ProductsService',['$ionicSideMenuDelegate', '$http', 'ApiEndpoint', '$ionicTabsDelegate', '$ionicSlideBoxDelegate', '$stateParams', 'AuthService', function($ionicSideMenuDelegate, $http, ApiEndpoint, $ionicTabsDelegate, $ionicSlideBoxDelegate, $stateParams, AuthService){
var products = [];
var prod = [];
return {
GetProducts: function(){
return $http.get(ApiEndpoint.url + '/products', {}).then(function(response){
products = response.data.products;
return response;
});
},
GetProduct: function(productId){
angular.forEach(products, function(product, key){
$scope.prod = {}; //ERROR: $scope is not defined
if(product.id == productId){
prod = product;
return product;
}
})
return prod;
}
}
}])
..after I click the item that error appears..And the page doesnt show the details must shown..
I am not sure if I got your question.
Usally every View has its own Controller. So in your case one controller for the menu.html and for the productpage. Of course you can also use the same controller for both views.
If you want to use one controller for both views the controller can provide the data for both views.
If you want a controller for each view you have to share to data between the controllers. For sharing data between different controllers you can find a lot of help:
- Stackoverflow share data between controllers
- Thinkster using services to share data between controllers
In both solutions you had to call your api in this services. For that you should understand the angularjs concept of $q and promises:
Angularjs Documentation of $q
If could specifiy which data you want to call from which page to another, I can improve this answer.
EDIT:
Based on your comment I can add the following suggestion. In your products.html you want to display the details of a choosen product. Thats roughly said a master-detail-pattern. You can take a look at this: Master-Detail-Pattern.
You will have to change your state-config and add a state for the product-details. Something like that (you will have to change the code):
.state('productDetails', {
url: "/product/:id",
templateUrl: 'templates/product.html',
controller: 'yourCtrl'
});
In your controller you can get the given :id over the state-params:
var productId= $stateParams.id;
To achive that it works you also have to edit your menu.html. For every product you need a link which looks like:
{{product.name}}
This has to be wrapped in your ng-repeat. But that is all discribed on the given page.
Of course there are also other possibilities to do what you want.
I am a new to MVC an need a little help.
In my view I make an ajax post as below.
function PostCheckedPdf(e) {
var values = new Array();
$('input:checked').each(function () { values.push(this.value); });
$.post("/UnregisteredUserPreview/DownloadPdfInvoice",
{ checkedList: values });
}
This post the values of any checkboxes that are checked inside a third party Grid component (Telerik). The Action method receives the array fine and loops through each value rendering a pdf report and putting the report into a ZipStream which is attached to the Response. After the loop the zipstream is closed and I return View();
When the Action is invoked through the $.post it runs through the action method but nothing happens in the browser.
If I call the Action through an action link (with a couple of hard coded value instead of passing the checked boxes values) the zip file with all the pdfs is downloaded.
What am I doing wrong or how can I post the checked values with an ActionLink?
Thanks in Advance!
Toby.
The difference is that your ActionLink is emitting an <a> tag, which is performing a GET operation. The browser interprets the contents of the response and opens the PDF.
Your jQuery method is performing a POST, but does nothing with the response, and thus silently throws it away in the background.
You need to actually do something with the return contents, like write it out to another window.
var w = window.open('', '', 'width=800,height=600,resizeable,scrollbars');
$.post("/UnregisteredUserPreview/DownloadPdfInvoice",
{ checkedList: values },
function(content){
w.document.write(content);
w.document.close(); // needed for chrome and safari
});
You are making an Ajax call to the server there and client side code should receive the returned result which seems that you are not doing there. It should be something like below :
$.ajax({
type: 'POST'
url: '/UnregisteredUserPreview/DownloadPdfInvoice',
data: { checkedList: values },
success: function (r) {
alert(r.result);
}
});
And assume that your controller is like below :
public ActionResult DownloadPdfInvoice() {
//do you stuff here
return Json(new { result = "url_of_your_created_pdf_might_be_the_return_result_here"});
}
NOTE
If you are posting your data with anchor tag, it is better to
prevent the default action of this tag so that it won't do anything
else but the thing you're telling it to do. You can do that by adding the
following code at the end of your click event function :
$("#myLink").click(function(e) {
//do the logic here
//ajax call, etc.
e.preventDefault();
});
Have a look at the below blog post as well. It might widen your thoughts :
http://www.tugberkugurlu.com/archive/working-with-jquery-ajax-api-on-asp-net-mvc-3-0-power-of-json-jquery-and-asp-net-mvc-partial-views
I have forms located in multiple areas in my layout page (not nested).
I have a partial view which performs a post to controller action.
What action result do I return in that post to keep the user on the current page?
Is jquery/ajax my only option? I would rather a solution that didn't depend on javascript, maybe even a solution that degrades nicely.
You can use the Request.Referrer property to see what page the user has come from and then just use that to redirect them back there.
This does introduce other issues, e.g. losing ModelState, so you'll have to design for that. Also note that some users can block sending referrer information in their requests to the server - so the Referrer property can be null.
I would recommend using AJAX and then falling back on this.
You just need to do a RedirectToAction("") back to your main view.
To post a form without submitting the whole page, which refreshes the browser, you need to use Ajax/jQuery. The degraded solution is to submit the whole page like you would with a normal form.
Here's how I do it with jQuery.
Html:
<div id="RequestButtonDiv">
<button id="RequestButton" name="Request" type="button">Request</button>
</div>
This calls AddToCart on my Request controller when the RequestButton button is clicked. The response is placed inside the RequestButtonDiv element.
<script type="text/javascript">
$(document).ready(function () {
$('#RequestButton').click(function (event) {
$('#RequestButton').text('Processing...');
$('#RequestButton').attr('disabled', true);
submitRequest();
});
});
function submitRequest() {
$.ajax({
url: '<%: Url.Action("AddToCart", "Request", new { id = Model.RowId, randomId = new Random().Next(1, 999999) } ) %>',
success: function (response) {
// update status element
$('#RequestButtonDiv').html(response);
}
});
}
</script>
Controller action:
public ActionResult AddToCart(int id)
{
var user = AccountController.GetUserFromSession();
user.RequestCart.AddAsset(id);
return View("~/Views/Assets/Details_AddToCart.ascx");
}
The controller returns a partial view. You could also return Content("some stuff") instead.
Holler if you have questions or need more detail.
I'm using ASP.Net MVC to create a web site which needs to do some processing (5 - 10 seconds) before it can return a view to the user. Rather than leaving the user staring at the glacial progress bar I'd like to show some sort of "Please Wait/We'll be right back" animated gif to keep them interested.
Does anyone know a good approach to achieving this?
(I found this answer but its not quite what I need, this uses jQuery to fetch data once the view has been returned. I'd like to display the "Please Wait" while they're waiting for the view to appear)
Thanks
I think the solution you referenced will work for you. You just need to have your initial controller action return right away with the "please wait message", then have the AJAX call do the actual retrieval of the contents based on your processing. If the request really takes 5-10 seconds you may also need to adjust the timeout value on the AJAX request so that it is able to complete. I don't know what the default timeout is but is may be less than what you need.
EDIT Example:
View code:
<script type="text/javascript">
$(document).ready( function() {
$.ajax({
type: "POST",
url: '<$= Url.Action("GetSlowData","Controller") %>',
data: 'id=<%= ViewData["modelID"] %>',
timeout: 15000, // wait upto 15 secs
success: function(content){
$("#container").html(content);
}
});
});
</script>
...
<div id="#container">
Please wait while I retrieve the data.
</div>
Controller
public ActionResult ViewMyData( int id )
{
ViewData["modelID"] = id;
return View();
}
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult GetSlowData( int id )
{
var model = ... do what you need to do to get the model...
return PartialView(model);
}
You'll also need a partial view (ViewUserControl) that takes your model and renders the view of the model. Note that this isn't complete -- you'll need to add error handling, you may want to consider what happens if javascript isn't enabled, ...
Hi im new to MVC and I've fished around with no luck on how to build MVC User Controls that have ViewData returned to them. I was hoping someone would post a step by step solution on how to approach this problem. If you could make your solution very detailed that would help out greatly.
Sorry for being so discrete with my question, I would just like to clarify that what Im ultimatly trying to do is pass an id to a controller actionresult method and wanting to render it to a user control directly from the controller itself. Im unsure on how to begin with this approach and wondering if this is even possible. It will essentially in my mind look like this
public ActionResult RTest(int id){
RTestDataContext db = new RTestDataContext();
var table = db.GetTable<tRTest>();
var record = table.SingleOrDefault(m=> m.id = id);
return View("RTest", record);
}
and in my User Control I would like to render the objects of that record and thats my issue.
If I understand your question, you are trying to pass ViewData into the user control. A user control is essentially a partial view, so you would do this:
<% Html.RenderPartial("someUserControl.ascx", viewData); %>
Now in your usercontrol, ViewData will be whatever you passed in...
OK here it goes --
We use Json data
In the aspx page we have an ajax call that calls the controller. Look up the available option parameters for ajax calls.
url: This calls the function in the class.(obviously) Our class name is JobController, function name is updateJob and it takes no parameters. The url drops the controllerPortion from the classname. For example to call the updateJob function the url would be '/Job/UpdateJob/'.
var data = {x:1, y:2};
$.ajax({
data: data,
cache: false,
url: '/ClassName/functionName/parameter',
dataType: "json",
type: "post",
success: function(result) {
//do something
},
error: function(errorData) {
alert(errorData.responseText);
}
}
);
In the JobController Class:
public ActionResult UpdateJob(string id)
{
string x_Value_from_ajax = Request.Form["x"];
string y_Value_from_ajax = Request.Form["y"];
return Json(dataContextClass.UpdateJob(x_Value_from_ajax, y_Value_from_ajax));
}
We have a Global.asax.cs page that maps the ajax calls.
public class GlobalApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "EnterTime", action = "Index", id = "" } // Parameter defaults (EnterTime is our default controller class, index is our default function and it takes no parameters.)
);
}
}
I hope this gets you off to a good start.
Good luck
I am pretty sure view data is accessible inside user controls so long as you extend System.Web.Mvc.ViewUserControl and pass it in. I have a snippet of code:
<%Html.RenderPartial("~/UserControls/CategoryChooser.ascx", ViewData);%>
and from within my CategoryChooser ViewData is accessible.
Not sure if I understand your problem completely, but here's my answer to "How to add a User Control to your ASP.NET MVC Project".
In Visual Studio 2008, you can choose Add Item. In the categories at the left side, you can choose Visual C# > Web > MVC. There's an option MVC View User Control. Select it, choose a name, select the desired master page and you're good to go.