First off, I am an ASP.NET MVC noob. It's my first project with ASP.NET MVC, so I am still learning. My background is mostly in WPF and XAML for the past two years.
So here is my problem: I have three cascading ListBoxes. The second listbox data is dependent on the first, and the third is dependent on the second. I want to use Ajax refreshes to fill the data in each list.
Here is my Index.cshtml:
#model WebApplication.Models.DevelopmentModel
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
</head>
<body class="body" scroll="auto">
<div class="page">
<div class="content">
<div id="lists">
#Html.Partial("DevelopmentListsView", Model)
</div>
</div>
</div>
</body>
</html>
My DevelopmentListsView.cshtml looks like this:
#model WebApplication.Models.DevelopmentModel
#using (Ajax.BeginForm("Index", "Development", new AjaxOptions() { UpdateTargetId = "lists" } ))
{
#Html.ListBoxFor(m => m.SelectedApplication, new SelectList(ViewBag.Applications), new { onchange = "this.form.submit();" })
#Html.ListBoxFor(m => m.SelectedVersion, new SelectList(ViewBag.Versions), new { onchange = "this.form.submit();" })
#Html.ListBoxFor(m => m.SelectedFlow, new SelectList(ViewBag.Flows) )
}
My Model looks like:
public class DevelopmentModel
{
public string SelectedApplication { get; set; }
public string SelectedVersion { get; set; }
public string SelectedFlow { get; set; }
}
And my Controller looks like this:
public class DevelopmentController : Controller
{
//
// GET: /Development/
public ActionResult Index()
{
FillViewBag();
return View(new DevelopmentModel());
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(DevelopmentModel model)
{
FillViewBag(model);
return PartialView("DevelopmentListsView", model);
}
private void FillViewBag(DevelopmentModel model = null)
{
//Magic to get all three lists dependent on the available data in the model:
ViewBag.Applications = applications;
ViewBag.Versions = versions;
ViewBag.Flows = flows;
}
}
Now, I want to use Ajax callbacks to retrieve the data, so it won't refresh every time, but when I click one of the Listbox items, the page then only shows the DevelopmentListsView view after that, not refreshing anything..
Can someone tell me what I am doing wrong?
Thanks for looking!
Figured out my own question:
I had two errors:
I missed the jquery script include in the Index.cshtml:
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
And I used the wrong submit (it should have been the jQuery submit):
$(this.form).submit()
The submit placed inside my models
#model WebApplication.Models.DevelopmentModel
#using (Ajax.BeginForm("Index", "Development", new AjaxOptions() { UpdateTargetId = "lists" } ))
{
#Html.ListBoxFor(m => m.SelectedApplication, new SelectList(ViewBag.Applications), new { onchange = "$(this.form).submit()" })
#Html.ListBoxFor(m => m.SelectedVersion, new SelectList(ViewBag.Versions), new { onchange = "$(this.form).submit()" })
#Html.ListBoxFor(m => m.SelectedFlow, new SelectList(ViewBag.Flows) )
}
Hope this helps someone some day ;).
Related
I want create a Master/Detail page that shows properties of the model as well items of properties of the same model that are collections. The page itself should only have one save button, that stores the values in a database. I also want to allow the the user to make changes to the collection properties, that are shown on the page without saving them into the database. The following code shows the setup for the picture collection, but I also want to do this for a "Child-table/grid" i.e. collection of "pocos". Is there a way to do this in MVC?
To my understanding, I would have to keep the instance of the object and pass it between the HTMLActions, as this instance holds all the changes.
Just some pointers in the right direction would be nice or, if the case, pointing out, that MVC should not be used for this...
The model:
public class MasterModel : ModelBase
{
public MasterModel()
{
}
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private ListBase<PicModel> pics;
public ListBase<PicModel> Pics
{
get { return pics; }
set { pics = value; }
}
}
Controller:
public ActionResult Edit(int id)
{
if (id <= 0 )
{
return RedirectToAction("Index");
}
m = new MasterModel (id);
return View(m);
}
[HttpPost]
public ActionResult NewPic(int id, HttpPostedFileBase uploadFile)
{
PicModel p = new PicModel();
MemoryStream ms = new MemoryStream();
uploadFile.InputStream.CopyTo(ms);
b.Picture= ms.ToArray();
m.Pics.Add(b); //Here it fails, as the MasterModel m is a different one then when the ActionResult Edit is called
}
View:
#model app1.Models.MasterModel
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/index.js")" type="text/javascript"></script>
<script>
$("#PicForm").on("submit", function (e) {
e.preventDefault();
var form = $(this);
var formData = new FormData(form.get(0));
$.ajax({
url: form.attr("action"),
method: form.attr("method"),
data: formData,
processData: false,
contentType: false
})
});
</script>
<div class="col-md-4 col-lg-4">
#using (Html.BeginForm("NewPic", "MasterModel ", FormMethod.Post, new { id = "PicForm", enctype = "multipart/form-data" }))
{
#Html.HiddenFor(model => model.Id)
<div class="container-fluid">
#foreach (app1.Models.PicModel b in Model.Pics)
{
var base64 = Convert.ToBase64String(b.Picture);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
<img src="#imgSrc" width="200" height="200" />
}
</div>
<div>
<input type="file" id="uploadFile" name="uploadFile" />
<input type="submit" value="uploadFile" class="submit" />
</div>
}
</div>
Update 06.01.2018:
What works in MVC5 is to use the sessionString. However, I've learned that this won't work in asp.net Core.
Set:
m = (MasterModel )System.Web.HttpContext.Current.Session["sessionString"];
Get:
System.Web.HttpContext.Current.Session["sessionString"] = m;
or, ..., that MVC should not be used for this...
Pure MVC won't cut it, and you're already on your way with the Ajax calls.
But you'll find that that gets more and more complicated.
The best route would be to study up on SPA, with for instance Angular.
What works in MVC5 is to use the Session[].
Yes, but that is server-side state manangment, problems with scale-out etc.
But usable, for ASP.NET Core you could use the MemoryCache, or step up to ReDis. You still have (can configure) a Session Id.
With a SPA you won't need the cache/session so much, just use it for optimization.
Try TempData to store your Data and access in next Request.
Currently we have a page where you select some parameters and click on a button to load data and display it in a grid, but there is no functionality to display the data on page load (via url parameters) yet. I've added the necessary routing configurations and Action, but I'm having troubles to render the page, it only displays the PartialView without styles.
How can I get the whole page to render and not just the PartialView?
Below is my simplyfied code for the View and Controller.
Views/Planing/Index.cshtml
#model PlaningTool.Web.Models.PlaningViewModel
<div class="row">
<div>
#using (Ajax.BeginForm("GetDataRows",
"Planing",
new AjaxOptions
{
HttpMethod = "Get",
UpdateTargetId = "gridPlaceholder",
LoadingElementId = "loadingIndicator"
}))
{
<!-- some comboboxes to select project and year -->
<input type="submit" value="Load data" />
}
</div>
</div>
<div id="gridPlaceholder">
<div id="loadingIndicator" style="display: none;">
<img src="~/Content/images/loading-image.gif" />
</div>
</div>
Controllers/PlaningController.cs
public partial class PlaningController : Controller
{
public virtual ActionResult Index()
{
return View();
}
public virtual ActionResult Plan(long projectID, int year)
{
var viewModel = new PlaningViewModel
{
ProjectID = projectID,
Year = year
};
// return GetDataRows(viewModel);
return RedirectToAction("GetDataRows", viewModel);
}
[RestoreModelStateFromTempData(typeof(PartialViewResult))]
public virtual PartialViewResult GetDataRows(PlaningViewModel viewModel)
{
// Load data from database with viewModel.ProjectID
// and viewModel.Year as parameters
[...]
var vm = new PlaningViewModel
{
// Set ViewModel for loaded data
[...]
};
return PartialView("Shared/_PlaningViewModelRows", vm);
}
[...]
}
I finally found a solution. I'm pretty sure it's not the best way to do this but it works.
If the Model is already set I render the PartialView.
<div id="gridPlaceholder">
#{
if (Model != null)
{
Html.RenderPartial("Shared/_PDataViewModelRows", Model);
}
}
<div id="loadingIndicator" style="display: none;">
<img src="~/Content/kendo/Bootstrap/loading-image.gif"/>
</div>
</div>
And in my Controller I've changed to this, so my ViewModel gets loaded independently and I simply return the same view as I would for Index with the new ViewModel.
public virtual ActionResult Plan(long projectID, int year)
{
var viewModel = new PlaningViewModel
{
ProjectID = projectID,
Year = year
};
return View("Index", LoadViewModel(viewModel));
}
public PlaningViewModel LoadViewModel(PlaningViewModel viewModel)
{
// Load data from database with viewModel.ProjectID
// and viewModel.Year as parameters
[...]
var vm = new PlaningViewModel
{
// Set ViewModel for loaded data
[...]
};
return vm;
}
I am new to MVC/Razor/Web and am hoping to eventually be able to edit a list of items, right now I am just trying to display these items using Html.BeginCollectionItem and it is not working (no error, just does not display my items.) I have listed my code below:
Model:
namespace EditList
{
public class GiftModel
{
public string Name { get; set; }
public double Price { get; set; }
}
}
Controller:
namespace EditList
{
public class GiftController : Controller
{
public ActionResult Index()
{
GiftModel[] initalData = new[]
{
new GiftModel{Name = "Tall Hat", Price = 39.95},
new GiftModel{Name = "Long Cloak", Price = 120.00}
};
return View(initalData);
}
}
}
Main View:
#{
Layout = null;
}
#model IEnumerable<GiftModel>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<h2>Gift List</h2>
What do you want for your birthday?
#using(Html.BeginForm())
{
<div id="EditorRows">
#foreach (var item in Model)
{
Html.RenderPartial("GiftEditorRow", item);
}
</div>
<input type="submit" value="Finished"/>
}
</body>
</html>
Partial View:
#model GiftModel
<div class="editorRow">
#using(Html.BeginCollectionItem("gifts"))
{
<div>HELLO</div>
Html.DisplayFor(m => m.Name);
Html.TextBoxFor(m => m.Name);
//Html.TextBoxFor(m => m.Price, new { size = 4 });
}
</div>
One thing to note is i did step into my main view and there is data in "items", but the partial view does not display the textboxes ect.. Im new to web code so i'm hoping I am missing something simple (I have looked at many tutorials and maybe i'm just overlooking something)
Let me know if there is any additional info I can provide.
Good day
I am working with 7 partial views on my index page.
Index.cshtml (code section that creates the partial views in their own tabs)
#model project1.Models.MasterModel
<div class="tab-content col-lg-9 col-md-9 col-sm-9 col-xs-9" style="margin-bottom:110px;">
<div id="partial1" class="tab-pane fade in active">
#Html.Partial("partial1", Model)
</div>
<div id="partial2" class="tab-pane fade in">
#Html.Partial("partial2", Model)
</div>
<div id="partial3" class="tab-pane fade in">
#Html.Partial("partial3", Model)
</div>
<div id="partial4" class="tab-pane fade in">
#Html.Partial("partial4", Model.Owners)
</div>
<div id="partial5" class="tab-pane fade in">
#Html.Partial("partial5", Model)
</div>
<div id="partial6" class="tab-pane fade in">
#Html.Partial("partial6", Model)
</div>
<div id="partial7" class="tab-pane fade in">
#Html.Partial("partial7", Model)
</div>
On partial1 I have a submit button that should populate the other partial views with the information that is submitted on the first partial view.
My Model consist of 7 models (one for each partial view)
MasterModel.cs
public class MasterModel
{
public DisplayPartial1 view1 {get;set;}
public DisplayPartial2 view2 {get;set;}
public DisplayPartial3 view3 {get;set;}
public DisplayPartial4 view4 {get;set;}
public DisplayPartial5 view5 {get;set;}
public DisplayPartial6 view6 {get;set;}
public DisplayPartial7 view7 {get;set;}
}
In my controller's Index Action result I create a new instance of the MasterModel and then I create new instances for all the sub models and return to the Index view.
MainController.cs
// Global variable used and returned by all partial views
MasterModel main = new MasterModel();
public ActionResult Index()
{
MasterModel master = new MasterModel();
master.view1 = new DisplayPartial1 ();
master.view2 = new DisplayPartial2 ();
master.view3 = new DisplayPartial3 ();
master.view4 = new DisplayPartial4 ();
master.view5 = new DisplayPartial5 ();
master.view6 = new DisplayPartial6 ();
master.view7 = new DisplayPartial7 ();
return View(master);
}
public ActionResult MyPartial1()
{
return PartialView("MyPartial1", master);
}
[HttpPost]
public ActionResult MyPartial1(MasterModel model, string submitButton)
{
if(submitButton == "GetInfo")
{
/*Process input values*/
//wcf service return data
main.view1.id = serviceObject.Id;
...
main.view4.name = serviceObject.Name;
...
}
return PartialView("MyPartial1", master);
}
When MyPartial1 is returned then the other 6 partial view do not update with the assigned information until I do a submit call with a java script that looks like the following:
<script type="text/javascript">
$(document).ready(function () {
$('#input1').change(function () {
$('form').submit();
});
$('#input2').change(function () {
$('form').submit();
});
});
</script>
An Example Partial view (all the partial views work on the same principals)
#model OperatorLicense.Models.MasterModel
#using (Ajax.BeginForm("MyPartial1", "Operator", null, new AjaxOptions
{
UpdateTargetId = "MyPartial1",
InsertionMode = InsertionMode.Replace,
HttpMethod = "Post"
}, new { id = "MyPartial1" }))
{
#Html.TextBoxFor(model => model.view1.SerialNumber, new { id="SerialNumber", #class = "form-control", placeholder = Html.DisplayNameFor(n => n.view1.SerialNumber) })
...
}
Is there a way to refresh the other partial views when the MyPartial1 partial view has returned so that the assaigned values can be displayed on the required partial view?
You can use OnSuccess or OnComplete property of AjaxOptions class.
#using (Ajax.BeginForm("MyPartial1", "Operator", null, new AjaxOptions
{
UpdateTargetId = "MyPartial1",
InsertionMode = InsertionMode.Replace,
HttpMethod = "Post",
OnSuccess="partial1Success"
}, new { id = "MyPartial1" }))
{
#Html.TextBoxFor(model => model.view1.SerialNumber, new { id="SerialNumber", #class = "form-control", placeholder = Html.DisplayNameFor(n => n.view1.SerialNumber) })
...
}
define partial1Success method in javascript
<script type="text/javascript">
function partial1Success(){
// write your other partial view refresh logic here
}
</script>
partial1Success method called after from submit successfully.
I'm developing an mvc 4 application and I'm just about done. I have two controllers are there.
public ActionResult Index()
{
return View(new Resources());
}
public ActionResult ResourceDetails(int id = 1)
{
ResourceItems re = new Resources().GetResDetails(id);
return View(re);
}
ResourceDetails is a partial viewpage .it contains
#model ....Models.ResourceItems
<div>
#Html.Raw(#Model.Res_Details)
</div>
and index page contains
#model IEnumerable<.....Models.ResourceItems>
<ul id="res">
#foreach(var Item in Model)
{
<a href="~/Resources/ResourceDetails/#Item.Id" ><li>#Item.Res_NA</li></a>
}
</ul>
<div id="rescontent">
</div>
I want load the partial page in to the div "rescontent" based on Id. Defaultly Id is 1. how it possible
You could use AJAX:
#model IEnumerable<Puthencruz.Rotary.Club.Models.ResourceItems>
<ul id="res">
#foreach(var item in Model)
{
<li>
#Html.ActionLink(
item.Res_NA,
"ResourceDetails",
"Resources",
new { id = item.Id },
new { #class = "detail" }
)
</li>
}
</ul>
<div id="rescontent">
</div>
and then in a separate javascript file you could use jQuery to subscribe to the .click event of the anchors and send an AJAX request to the Details controller action sending the current item id and then render the results in the #rescontent div:
$(function() {
$('.detail').click(function() {
$('#rescontent').load(this.href);
return false;
});
});
Also from your controller action make sure you are returning a partial view:
public ActionResult ResourceDetails(int id = 1)
{
ResourceItems re = new Resources().GetResDetails(id);
return PartialView(re);
}