I have a following form:
Edit is some partial view _Edit with separate view model called EditVM.
Search is a partial view _Search split between two another partial models - filter (_SearchFilter) and search results (_SearchResults). All those views share one view model SearchVM.
Finally I'm trying to make an UpdateVM which represents what's on the picture. It contains EditVM and SearchVM instances.
My problem is loosing information about the UpdateVM.
First I'm calling get action Update.
[HttpGet]
public virtual ActionResult Update()
{
var model = new UpdateVM();
var searchVM = new SearchVM();
model.searchVM = searchVM;
var editVM = new EditVM();
model.editVM = editVM;
return View(model);
}
View looks like that:
#model UpdateVM
#Html.Partial(MVC.Shared.Views._Search, Model.searchVM)
#Html.Partial(MVC.Shared.Views._Edit, Model.editVM)
Problem begins with searching on the filter. As you can see to the _Search partial view only a SearchVM is passed. I want Search to be generic, shared between the views, so I can't pass to it the UpdateVM.
Filter view _SearchFilter looks as follows:
#using (Html.BeginForm(Model.SearchButtonAction, Model.SearchButtonController, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="frm_row">
#Html.TextBoxFor(model => model.Query)
<input type="submit" value="Search" />
</div>
}
The problem is that post action is getting SearchVM instance, moreover with only Query field set. Is it possible at all to split whole view shown on the picture only between two actions, get and post, with UpdateVM? Is it possible to don't loose the information already stored in the models (search has some settings, for example mode small or big)?
Or maybe there's other way to implement mentioned view in a robust way? Maybe I'm trying to do it not in the MVC style?
You don't want to load your partial views into the main view. you want them to be dynamically loaded based on the search parameters. To do this use an ajax call
$(document).on('click', '.btnSearch', function(){
$.ajax({
url: '#Url.Action("Search", "Controller")',
type: 'post',
cache: false,
async: true,
data: { id: $("#Query").val() },
success: function(result){
$(".divSearch").html(result);
}
});
});
your controller would look like this
public PartialViewResult Search(int id){
var Model = //populate the model based on the selected id
return PartialView("_partialName", Model);
}
and change your search button to
<input type="button" value="Search" class="btnSearch" />
you don't want to submit the form so you want a button instead of a submit and you need to add a class to the button that your script can trigger off of for the click event. Let me know if you have any questions.
Related
I have a C# MVC web form with a fairly complex hierarchy of data. I need to select a portion of that data, a sub-collection of objects, and send it to an Action where I can manipulate the collection and return a partial view. All of this is old-hat, except I can't figure out how to select the sub-collection with JQuery.
Example:
Orders.Customers
// For simplicity, Customer has the following properties
public class Customer
{
public int Id { get; set;}
public string Name { get; set;}
}
On the Razor view, you end up with elements that look like this:
<input name="Order_Customers[0].Id" id="Order.Customers[0].Id" type="hidden" value="154' />
<input name="Order_Customers[0].Name" id="Order.Customers[0].Name" type="hidden" value="John Smith' />
<input name="Order_Customers[1].Id" id="Order.Customers[1].Id" type="hidden" value="176' />
<input name="Order_Customers[1].Name" id="Order.Customers[1].Name" type="hidden" value="Kendra Wallace' />
I only need to pass the sub-collection of Customers to an action that looks something like this:
public ActionResult AddCustomer(IList<Customer> customers)
{
// Do some work on the collection, add/remove members, etc.
return PartialView("_Customers", customers);
}
The part I can't figure out is the JQuery selection. I've tried variations of this but I can't get any of them to work:
var customers = $("input[name^='Order_Customers']".toArray(); // ?
var customers = $("input[name^='Order_Customers[]']".toArray(); // ?
If the selected inputs are not already in a form, create one:
var $form = $('<form>');
Append the elements you found with jQuery to that new form and then make a new FormData object with the populated form:
var formData = new FormData($form);
You can then pass that formData directly to the AJAX url and MVC will deserialize/bind the submitted data to the list of Customers.
url: '#Url.Action("UploadImage")',
type: 'POST',
data: formData,
You'll also need to change the paramter of your action so that MVC can map the properties to Order.Customers or change the name property in the HTML of those fields to be like Customer[0].Name.
I need to pass a parameter to a partial view but I'm not finding how.
So basically my problem is: I need to call RenameFileAndFolder from a different view and then bring the user to the Index controller page but passing a path to the _fileTable.
Controller:
public ActionResult Index(){...}
public ActionResult _fileTable(string path){...} //partial view
[HttpPost]
public ActionResult RenameFileAndFolder(string path, string newName){...}
View:
function RenameFileFolder() {
//(...)
$.ajax({
type: "Post",
url: '#Url.Action("RenameFileAndFolder", "ManageFiles")',
data: { path: '#(currentPath)', newName: inputName },
dataType: "json",
traditional: true,
success: function (data) {
document.getElementById("inputNewName").value = "";
//Here how can I say: "go to the index page with the path="X" on the partial view"?
//currently I am doing this but it does not allow me to pass a parameter
window.location.assign("Index");
})
}
The partial view is called within the view:
<div id="tabelaDiv">
#{
Html.RenderAction("_fileTable", Model);
}
</div>
EDIT:
My situation in more detail:
So, I am on the View beta with partial view omega within it. Then I go to View alpha and call function RenameFileFolder() with an ajax query, and, if success, I want to be able to go again to View Beta and pass a parameter to the partial view omega.
Simply write this to send parameters to ActionMethod
<div id="tabelaDiv">
#Html.Action("_fileTable",new{path= "your path"} )
</div>
You could try storing the new filepath in a Session variable and then accessing it in your view. This will save you trouble of trying to pass the variable between your views.
[HttpPost]
public ActionResult RenameFileAndFolder(string path, string newName)
{
//code to get new file path
//set session variable
Session["path"] = "<filepath>";
//return your ActionResult;
}
Once you have stored the variable, you can access the session variable in your view by using:
#Session["path"]
It really depends on how long you would like this data to persist for. This variable will persist throughout the users entire session, so if you want to reset it you would need to do so explicitly Session["path"] = null. However, if you only want it to persist long enough to render a single partial view, it may be better to use one of the other methods for persisting data such as ViewData:
https://www.codeproject.com/Articles/576514/AplusBeginner-splusTutorialplusonplusVariousplus
I am trying to set up a simple login html page, whose action is sent to mvc controller on another of my sites. I have no problem setting up the page to do the post, and in the mvc controller I have my method that reads the form post. The problem is that I am not seeing my fields from the html form in the form collection.
Is there something special that I need to do to read a form post within a mvc controller method, if so what is that?
The is the form action markup from my page
<form action="http://reconciliation-local.sidw.com/login/launch" method="post">
User Name <input type="text" id="username"/><br/>
Password <input type="text" id="password"/>
<input type="submit" value="launch"/>
</form>
The controller method
[HttpPost]
public ActionResult launch(FormCollection fc)
{
foreach (string fd in fc)
{
ViewData[fd] = fc[fd];
}
return View();
}
When I step through the controller method code, I am not seeing anything in the formcollection parameter.
Post Html To MVC Controller
Create HTML page with form (don't forget to reference a Jquery.js)
<form id="myform" action="rec/recieveData" method="post">
User Name <input type="text" id="username" name="UserName" /><br />
Password <input type="text" id="password" name="Password"/>
<input type="submit" id="btn1" value="send" />
</form>
<script>
$(document).ready(function () {
//get button by ID
$('#btn1').submit(function () {
//call a function with parameters
$.ajax({
url: 'rec/recieveData', //(rec)= Controller's-name
//(recieveData) = Action's method name
type: 'POST',
timeout: '12000', (optional 12 seconds)
datatype: 'text',
data: {
//Get the input from Document Object Model
//by their ID
username: myform.username.value,
password: myform.password.value,
}
});
});
});
</script>
Then in The MVC Controller
controller/action
| |
1. Create Controller named rec (rec/recieveData)
Create View named rec.cshtml
Here is the controller:
public class recController : Controller
{
// GET: rec
string firstname = "";
string lastname = "";
List<string> myList = new List<string>();
public ActionResult recieveData(FormCollection fc)
{
//Recieve a posted form's values from parameter fc
firstname = fc[0].ToString(); //user
lastname = fc[1].ToString(); //pass
//optional: add these values to List
myList.Add(firstname);
myList.Add(lastname);
//Importan:
//These 2 values will be return with the below view
//using ViewData[""]object...
ViewData["Username"] = myList[0];
ViewData["Password"] = myList[1];
//let's Invoke view named rec.cshtml
// Optionaly we will pass myList to the view
// as object-model parameter, it will still work without it thought
return View("rec",myList);
}
}
Here is the View:
#{
ViewBag.Title = "rec";
}
<h2>Hello from server</h2>
<div>
#ViewData["Username"]<br /> <!--will display a username-->
#ViewData["Password"] <!-- will display a password-->
</div>
If you posted some code it would be much easier to help you, so please edit your question...
Make sure that your form's action has the correct address, that your method is specifying POST (method="POST") and that the input fields under your form have name attributes specified.
On the server side, try making your only parameter a FormCollection and test that the fields in your form posted through the debugger. Perhaps your model binding isn't correct and the FormCollection will at least show you what got posted, if anything.
These are just common issues I've seen. Your problem could be different, but we need to see what you're working with to be able to tell.
Try something like this:
cQuery _aRec = new cQuery();
_aRec.Sqlstring = "SELECT * FROM Admins";
DataSet aDS = _aRec.SelectStatement();
DataTable aDT = aDS.Tables[0];
foreach (DataRow aDR in aDT.Rows){
if (txtAdminUsername.Text == aDR[0].ToString()){
if (txtAdminPassword.Text == aDR[1].ToString()){
Session["adminId"] = aDR[0];
Response.Redirect("Admin.aspx");
return;
}
}
}
Make sure that your FormCollection object properties for username and password are defined properly.
I had to use the name attribute on the text tag, and that solved my problem, is now working like a charm.
You have to use Ajax to do that.. Whenever you want to "submit" from client side, you should use Ajax to update the server
Step 1 - you redirect your Ajax call to your action, but with your list of parameters in the query-string appended
$.ajax(url: url + "?" + your_query_string_parameter_list_you_want_to_pass)
Step 2 - add optional parameters to your Controller-action with the same names and types you expect to get returned by the client
public ActionResult MyControllerAjaxResponseMethod(type1 para1 = null,
type2 para2 = null,
type3 para3 = null, ..)
Know that the optional parameters have to be initialized, otherwise the Action itself will always ask for those
Here's where the "magic" happens though --> MVC will automatically convert the query-string parameters into your optional controller-parameters if they match by name
I was also looking for a good answer for this, --> i.e. - one that doesn't use q-s for that usage, but couldn't find one..
Kinda makes sense you can't do it in any other way except by the url though..
I have a simple question (may not be a simple answer!) with the WebGrid in MVC4.
I have a functional Grid like so
<div id="Submitted">
#Html.Grid(
Model.Submitted, displayHeader: false, fieldNamePrefix: "Submitted_", ajaxUpdateContainerId: "Submitted",
columns: new WebGridColumn[]{
new WebGridColumn(){ ColumnName = "Date",Header = "Date",Style = "",CanSort = false,Format = x => x.Date.ToString(Globals.Default.DATEFORMAT) },
new WebGridColumn(){ ColumnName = "ID",Header = "Review",Style = "", CanSort = false, Format = x=>#Html.ActionLink("Review","Review","Company",new{ID = x.ID },new{}) }
})
</div>
When reloading the "Submitted" div with Ajax when the next page button is clicked, it generates the next page fine - but it's going to the original action on the controller, which should be a full page.
How does it filter out everything other than the grid itself? with some clever C# code or jQuery?
EDIT:
To clarify, I'm not asking how to do the paging better, or myself, as far as I'm concerned the default paging with the webgrid is working perfectly as it should - I'm asking how the WebGrid does it's ajax paging when posting back to an action which is returning a FULL page.
It does this using jquery load() and functionality that allows it to select just the relevant incoming nodes. This is taken from http://msdn.microsoft.com/en-us/magazine/hh288075.aspx
To allow the script to be applied just to a WebGrid, it uses jQuery selectors to identify elements with the ajaxGrid class set. The script establishes click handlers for the sorting and paging links (identified via the table header or footer inside the grid container) using the jQuery live method (api.jquery.com/live). This sets up the event handler for existing and future elements that match the selector, which is handy given the script will be replacing the content.
You should put your grid in a partialview and update it by Ajax. In controller you should find the request's type. If it is a ajax request(by Request.IsAjaxRequest() ) you must return the partialview, otherwise you must return the original view.
If you are using ajax.beginform you must do something like this:
#using (Ajax.BeginForm("Index", new AjaxOptions { OnFailure = "searchFailed", HttpMethod = "POST", UpdateTargetId = "Submitted" }))
{
...
}
<div id="Submitted">
#Html.Partial("_partialviewname", Model)
</div>
rn
and in controller:
public ActionResult Index(int? page)
{
...
if (Request.IsAjaxRequest())
{
return PartialView("_partialviewname", db.model)
}
return View(db.model)
}
I am new at .NET mvc.
In a view "DisplayThings" I have something like:
#foreach (var thing in Model)
{
#Html.Partial("DisplayPartial", thing)
}
In the partial view "DisplayPartial" I have
#using (Ajax.BeginForm("Afunc", new AjaxOptions ()))
{
#Html.EditorFor(model => model.AstringThing)
#Html.EditorFor(model => model.AintThing)
<input type="submit" name="submit" value="Ajax Post" />
}
At the moment the "Afunc"-Action saves the model to the database and then redirects to a controller action to retrieve all "things" from the database and render the entire "Displaythings" View.
My question is: When i press one of the submitbuttons (There is one submitbutton for every "thing" i the list). I want only that partial view to reload/reflect on my change. I dont want to reload the entire "Displaythings" view. How do I do this? If I just return a partial view I lose everything else but that partial view.
If this is a bad approach please give me directions.
Update:
I am still doing something wrong as I get the partial view rendered in a new page. My controller :
public ActionResult Afunc(ThingModel thingmodel)
{
// do
return PartialView("DisplayPartial", thingmodel);
}
I have tried using UpdateTargetId and onsuccess both with the same result (A new page)
In the AjaxOptions that your are simply now passing as new AjaxOptions you can specify the target element using the UpdateTargetId property:
<div id="unique_thing_id">
#using (Ajax.BeginForm("Afunc", new AjaxOptions { UpdateTargetId = 'unique_thing_id' }))
{
}
</div>
Above, a container with unique id for every "thing" is represented with <div id="unique_thing_id">. This will be replaced with the repsonse of the request. Change Afunc to render only the particular "thing" partial.