Render whole page with PartialView (and data) on page load - c#

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;
}

Related

How to pass the model items between MVC Actions

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.

Counting how many times a button was clicked

I am wondering how can I count the number of times a button in my view was clicked using sessions and not using jQuery, just asp.net.
Here is my action method (empty) :
public ActionResult ClickCounter()
{
return View();
}
and my view :
#{
ViewBag.Title = "ClickCounter";
}
<h2>ClickCounter</h2>
#using (#Html.BeginForm())
{
<!-- form content here -->
#Session["num"] = 0;
<form method="post">
<fieldset>
<legend>Button clicks counter</legend>
<div>
<label for="Clciks">Clicks:</label>
<h2>#Session["num"]</h2>
</div>
<div>
<label> </label>
<input type="submit" value="Click!" class="submit" />
</div>
</fieldset>
</form>
}
Excuse me for the lame questions, but I am a complete novice and trying to understand how this stuff work. I tried googleing.
I just want to display the click count in the h2 in my view using sessions for the purpose.
Any tips will be appreciated.
If it is for simply increasing the clicked count on form submit, You can update your http post action method to read the session value if exist and increase and set it back. If not exist, initialize it.
const string sessionVariableName = "num";
public ActionResult ClickCounter()
{
if (Session[sessionVariableName] == null)
{
Session[sessionVariableName] = 0;
}
return View();
}
[HttpPost]
public ActionResult ClickCounter(string dummyParam)
{
if (Session[sessionVariableName] == null) // should not happen!
{
Session[sessionVariableName] = 0;
}
else
{
var n = (int)Session[sessionVariableName];
n++;
Session[sessionVariableName] = n;
}
return View();
}
Make sure that you are doing a GET form method on submit.
You also need to remove the (re) initialization in the view this line #Session["num"] = 0; as we are doing that in the action method. Also you should not have nested forms as it is invalid. Html.BeginForm helper will render the markup for the form tag. So remove the inner form tag you have.
You have tagged this question as asp.net-mvc, why not take advantage of the framework?
Model
class MyModel
{
public int ClickCount { get; set; }
}
View
#model MyModel
#{
ViewBag.Title = "ClickCounter";
}
<h2>#ViewBag.Title</h2>
<form method="post">
<!-- hidden input of the current click count -->
#Html.HiddenFor(m => m.ClickCount)
<fieldset>
<legend>Button clicks counter</legend>
<div>
#Html.LabelFor(m => m.ClickCount)
<h2>#Model.ClickCount</h2>
</div>
<div>
<button type="submit">Submit!</button>
</div>
</fieldset>
</form>
Controller
const string clickCountSessionKey = "clickCount";
[HttpGet]
public ActionResult ClickCounter()
{
// initialize the model
var model = new MyModel() { ClickCount = 0 };
var previousClickCount = Session[clickCountSessionKey];
if (previousClickCount != null)
{
model.ClickCount = (int)previousClickCount;
}
return View(model);
}
[HttpPost]
public ActionResult ClickCounter(MyModel model)
{
// increment the click count of the model
model.ClickCount++;
// track the click count in the session
Session[clickCountSessionKey] = model.ClickCount;
return View(model);
}

Passing Data from one controller method to another in MVC

I have a page that has 2 text boxes First Name and last Name after user click on sign up button API will run and returns user info and shows another page(view) that had user Phone, email,.. That fill with the info that API returns. I have 1 controller and 2 views.
I get the info from API and return the second view but not sure how fill the text boxes with the info I have. The problem is using the models in view, I have 2 models one for each view. I am getting this error when I call the second view:
The model item passed into the dictionary is of type 'System.Collections.Generic.Dictionary`2[System.String,System.Object]', but this dictionary requires a model item of type Models.CreateLogInRequest'.
This is my controller:
[HttpGet]
public ActionResult SearchUser()
{
return View();
}
[HttpPost]
public async Task<ActionResult> SearchUser(UserSearchRequest userSearchRequest)
{
HttpClient client = new HttpClient();
object userObject = null;
string baseUrl = "http://test/api/users";
if (userSearchRequest.FirstName != null && userSearchRequest.LastName)
{
var response = await client.GetAsync(string.Format("{0}{1}/{2}/{3}", baseUrl, "/users", userSearchRequest.FirstName, userSearchRequest.LastName));
if (response.IsSuccessStatusCode)
{
userObject = new JavaScriptSerializer().DeserializeObject(response.Content.ReadAsStringAsync().Result) as object;
}
}
if (userObject != null)
{
return View("Create", userObject);
}
return View("Create", null);
}
[HttpPost]
public ActionResult Create(CreateLogInRequest createLogInRequest)
{
return View();
}
This is my First View that shows 2 text boxes:
#using (Html.BeginForm("SearchUser", "SignUp", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input id="FirstName" name="FirstName" type="text" placeholder="First NAME" />
<input id="LastName" name="LastName" type="text" placeholder="LastName " />
<input id="btnSubmit" name="btnSubmit" type="submit" value="SIGN UP TODAY" />
}
and this is my model for 1st view:
public class UserSearchRequest
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
This is the second View:
#model Models.CreateLogInRequest
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm("create", "SignUp", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input id="Email" name="Email" type="text" placeholder="Email" value="#Model.Email" />
<input id="Phone" name="Phone" type="text" placeholder="Phone" value="#Model.Phone" />
<input id="btnSubmit" name="btnSubmit" type="submit" value="CREATE ACCOUNT" />
}
and this is Model for this view:
public class CreateLogInRequest
{
public string Email { get; set; }
public string Phone { get; set; }
....
}
See my comments and try this:
[HttpGet]
public ActionResult SearchUser()
{
return View();
}
[HttpPost]
public async Task<ActionResult> SearchUser(UserSearchRequest userSearchRequest)
{
HttpClient client = new HttpClient();
CreateLogInRequest userObject = null;
string baseUrl = "http://test/api/users";
if (userSearchRequest.FirstName != null && userSearchRequest.LastName)
{
var response = await client.GetAsync(string.Format("{0}{1}/{2}/{3}", baseUrl, "/users", userSearchRequest.FirstName, userSearchRequest.LastName));
if (response.IsSuccessStatusCode)
{
userObject = new JavaScriptSerializer().DeserializeObject<CreateLogInRequest>(response.Content.ReadAsStringAsync().Result);
}
}
if (userObject != null)
{
return RedirectToAction("Create", userObject);
}
return View("Create", null);
}
[HttpPost]
public ActionResult Create(CreateLogInRequest createLogInRequest)
{
return View();
}
In the Controller you can create a new instance of Models.CreateLogInRequest model and fill the related properties received from 1st View. If Models.CreateLogInRequest does not contain such properties then it is better to load these values by using TempData or ViewBag in the Controller retrieved from the 1st View and pass them to the 2nd View. For the differences between ViewBag, ViewData, or TempData you might have a look at When to use ViewBag, ViewData, or TempData in ASP.NET MVC 3 applications. Hope this helps...

Not able to run another function for another button inside same view

I have got the two buttons in the same view one is working with the data to show in a label in another view and I have written the function for the button2 (adding another value), when I click on the button2 its not showing the data in view ..... rather it's giving error like this ... http:404 Resource not found error
and this is the view
#model MvcSampleApplication.Models.products
#{
ViewBag.Title = "Valuesadd";
}
<h2>Valuesadd</h2>
#using (Html.BeginForm("SubmitValue","EnterValue",FormMethod.Post))
{
<div>
<fieldset>
<legend>Enter Textbox Value</legend>
<div class ="editor-label">
#Html.LabelFor(m => m.EnteredValue)
</div>
<div class="editor-field">
#Html.TextBoxFor(m=>m.EnteredValue)
</div>
<p>
<input type="submit" value="Submit1" />
</p>
</fieldset>
</div>
}
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
<p>
<input type="submit" value="Submit2" />
</p>
}
and this is the controller for
namespace MvcSampleApplication.Controllers
{
public class EnterValueController : Controller
{
[HttpPost]
public ActionResult SubmitValue(MvcSampleApplication.Models.products model)
{
TempData["logindata"] = model.EnteredValue;
return RedirectToAction("submittedvalues" , "SubmitValue2");
// how can we redirect to another view when the button is clicked in one view
}
public ActionResult submittedvalues()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = data;
return View(model);
}
// action for second button click
public ActionResult submittedvalues2()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = "HIIII"+data;
return View(model);
}
}
}
would you pls suggest any idea ..
Many thanks...
Your form action and action in the controller are not named the same. Also you don't have a HttpPostfor it
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
}
//add this
[HttpPost]
public ActionResult submittedvalues2()
{
var model = SOMETHING;
return View("submittedvalues", model);
}
or
[HttpPost]
public ActionResult submittedvalues2()
{
//Do your post actions and redirect to action
return RedirectToAction("submittedvalues");
}
SubmitValue2 in the form should be submittedvalues2, and add a HttpPost attribute on it

Load two controllers in the same view

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);
}

Categories

Resources