How to keep CheckBox value after a get? - c#

In my ASP.NET MVC 5 website i have this situation:
I have a GridView that i can get just the default rows or all the rows(including the deleted ones). Im trying to control that using a CheckBox in the ribbon of the view called 'cbxGetAll'.
So, here is my script:
<script>
function OnCommandExecuted(s, e) {
if (e.item.name == "cbxGetAll") {
if (e.parameter) {
window.location.href = '#Url.Action("Index",new {getAll = true})';
return;
} else {
window.location.href = '#Url.Action("Index",new {getAll = false})';
return;
}
}
</script>
And my Action:
public ActionResult Index(bool? getAll)
{
if (getAll != null && (bool) getAll)
{
//Return Without Filter
}
else
{
//Return With Filter
}
}
I change the getAll parameter in the URL and it works well.
But the problem is that when the ActionResult completes, it reloads the page (of course) and then i lost the checkbox state.
How can i deal with this?

It's all about view models. You should be returning a view model that has the value of your checkbox, and have your view use that value. If you are also returning data, simply place the data (whatever it is) inside your view model as well.
Example:
public class MyViewModel
{
public bool GetAll { get; set; }
public SomeDataModel[] MyData { get; set; }
}
public ActionResult Index(bool? getAll)
{
SomeDataModel[] data;
if (getAll != null && (bool) getAll)
{
var data = GetSomeData(true);
}
else
{
var data = GetSomeData(false);
}
return View(new MyViewModel() { MyData = data, GetAll = getAll == true });
}

Related

How to access class method from view in asp.net mvc c#?

I have controller : RecruitmentController.cs
and i have method/action : cekrecomended
public string cekrecomended(string id)
{
id = EncryptDecrypt.Decrypt(id);
string ada = "false";
string jurusan = Session["Jurusan"].ToString();
string pendidikan = Session["Pendidikan"].ToString();
int usia = Convert.ToInt16(Session["Usia"]);
string kelamin = Session["Kelamin"].ToString();
double nilai = Convert.ToDouble(Session["Nilai"]);
var data = (from c in db.ViewVacancyJabatanPerusahaans
where
c.Pendidikan.Contains(pendidikan) &&
(c.Jurusan.Contains(jurusan) || c.Jurusan.Contains("Semua jurusan")) &&
c.Nilai <= nilai &&
c.UsiaDari <= usia &&
c.UsiaSampai >= usia &&
c.JenisKelamin.Contains(kelamin) &&
c.TglAkhirlamaran >= DateTime.Now &&
c.Dlt == false &&
c.IDVancancy == Convert.ToInt16(id)
orderby c.IDVancancy descending
select c).Count();
if (data > 0)
{
ada = "true";
}
return ada;
}
i want to access cekrecomended from view.
#if(Human_Resource_Development.Controllers.RecruitmentController.cekrecomended(Convert.ToString(item.IDVancancy)) == "true")
{
<button>Apply this position</button>
}
but i get error.
This defeats the separation of model, view and controller MVC is based on - in your view you should just use your view model. In your case just use a view model that has a property making the result of this method call available.
You should use your view model for that purpose. Let's say MyViewModel is the class of your model, add a boolean property named IsRecommended
public class MyViewModel
{
// all of the other properties
// ....
public bool IsRecommended { get; set; }
}
Set the value of IsRecommended in your controller action method
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
// other codes here
// ...
model.IsRecommended = ....; // logic from cekrecomended method here
return View(model);
}
Make sure you have this syntax at the top of your view
#model MyViewModel
and determine whether the "Apply this position" button will be displayed or not based on the value of IsRecommended property as below
#if (Model.IsRecommended)
{
<button>Apply this position</button>
}
Thank you for your answers. My problem solved, i have solution.
i just change
public string cekrecomended(string id)
{
//bla bla
}
to
public static string cekrecomended(string id)
{
//bla bla
}
and i can access from view.

Pass ViewData to ActionResult using RedirectToAction in C# ASP.NET MVC Pattern

I have a form that once submitted will have some complex routing based on what is entered in combination with server side calculaitons. I want to pass data that is collected from the first form to second form via RedirectToAction.
At first I thought I could perform a RedirectToAction to pass the data via a POST method cleanly, but it appears there is no easy way to do this. Reading more I want to see if there is some easy way I can just pass a Hashtable or ViewData through an RedirectToAction to the proper ActionResult and just read the variables but that is proving more challenging than I thought.
Here is a simplified version of what I am trying it.
[AcceptVerbs("GET","POST")]
public ActionResult Step8(int id = 0, Hashtable FormValues = null) {
// was this a redirect back to us?
if (FormValues != null && FormValues.Count > 0) {
if (FormValues.ContainsKey("title") && FormValues["title"] != null) {
string _title = FormValues["title"].ToString();
}
}
// the form in thie view redirects to Step9
return View();
}
[AcceptVerbs("POST")]
public ActionResult Step9(int id = 0) {
bool issue_found = true;
if(issue_found){
// hypothetical issue found, back to previous step
Hashtable _FormValues = new Hashtable();
_FormValues.Add("title", "My Title");
_FormValues.Add("product", "My thing");
return this.RedirectToAction("Step8", _FormValues);
}else{
// .. do stuff
return View();
}
}
What am I doing wrong? How can I pass this data?
The approach was more complicated then it needed to be. TempData survives a Redirect so that is what I did. Here is a working solution:
[AcceptVerbs("GET","POST")]
public ActionResult Step8(int id = 0) {
string _product = "";
string _title = "";
// was this a redirect back to us?
try {
if (TempData != null) {
if (TempData.ContainsKey("product") && TempData["product"] != null) {
_product = TempData["product"].ToString();
}
if (TempData.ContainsKey("title") && TempData["title"] != null) {
_title = TempData["title"].ToString();
}
}
} catch {}
// The form in this view performs a POST to Step9
return View();
}
[AcceptVerbs("POST")]
public ActionResult Step9(int id = 0) {
bool issue_found = true;
if(issue_found){
// hypothetical issue found, back to previous step
TempData["title"] = "My Title";
TempData["product"] = "My thing";
return this.RedirectToAction("Step8");
}else{
// .. do stuff
return View();
}
}

How do I call a model function with Ajax (or something similar)?

I have a model that (among other things) returns a tabular representation of itself when a method - ToHtml() - is called.
LotSpace and LotRow are both models that (for brevity) I am not including. They actually make database calls, and are the reason I would like to redraw this lot using ajax calls. If they are relevant to this question I can add them.
public class Lot
{
public List<LotSpace> Spaces;
public List<LotRow> Rows;
public int SpacesPerRow
{
get
{
return (Spaces.Count / Rows.Count);
}
}
public Lot(int startSpace, int endSpace, int numberOfRows)
{
Spaces = LotSpace.ToList(startSpace, endSpace);
/***testing*****/
Spaces[0].Blocked = true;
Spaces[1].Blocked = true;
Spaces[2].Blocked = true;
Spaces[3].Blocked = true;
Spaces[4].Blocked = true;
Spaces[5].Blocked = true;
Spaces[6].Blocked = true;
Spaces[7].Blocked = true;
/***testing*****/
Rows = LotRow.ToList(numberOfRows);
LoadSpacesIntoRows();
}
private void LoadSpacesIntoRows()
{
foreach(var space in Spaces)
{
int rowIndex = 0;
while(rowIndex < Rows.Count)
{
if(Rows[rowIndex].Spaces.Count < SpacesPerRow)
{
Rows[rowIndex].Spaces.Add(space);
break;
}
rowIndex++;
}
}
}
public string ToHtml()
{
Table table = MapMaker.HTML.CreateTable(this);
MapMaker.HTML.AddSpaces(table, this);
return MapMaker.HTML.ControlToString(table);
}
}
Right now this is called from the view like this:
Controller
public ActionResult Index()
{
return View(new Lot(392, 1, 7));
}
View
<div class="row">
#Html.Raw(Model.ToHtml())
</div>
This works, but under certain circumstances, I would like to be able to redraw this map. Is it possible to make an ajax call from the view so that I can redraw this portion of the view on demand without necessitating a full page reload?
Yes. But AJAX doesn't "call a method on a model", it invokes a controller action. So, for example, you can create a new controller action with a new view which returns only that HTML:
public ActionResult Lot()
{
return View(new Lot(392, 1, 7));
}
And, aside from the #model declaration, the view would just be:
#Html.Raw(Model.ToHtml())
Now you have a URL which returns just the HTML for that table and nothing else. You can fetch it using something like the jQuery load() function:
$('#yourDiv').load('#Url.Action("Lot", "YourController")');
The AJAX request is a standard HTTP request like any other. You just need an endpoint on the server to handle that request and return a response.

Web Api How to Return Dynamically Created Image and text data simultaneously in same response

I would like to return an image that is dynamically created instead of retrieving from a database or from file. Let's say I have a simple ZipCode class. I would like to have a property that would return an image representation of the zipcode. The JSON returns "ZipAsImage":"System.Drawing.Bitmap".
Yes I am new to the programming in the web world. Yes I have looked for other examples but they seemed to only return an image. Thanks for any help.
public class ZipCode
{
public int ZipCodeId { get; set; }
[NotMapped]
public Image ZipAsImage
{
get
{
// Create a blank iamge for now to test.
return new Bitmap(50, 50);
}
set { }
}
}
My ApiController class
public class ZipCodesController : ApiController
{
private MyContext db = new MyContext();
// GET api/ZipCodesController
public IEnumerable<ZipCode> GetZipCodes()
{
return db.zipcodes.AsEnumerable();
}
// GET api/ZipCodesController/5
public ZipCode GetZipCode(int id)
{
ZipCode zipcode = db.ZipCodes.Find(id);
if (zipcode == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return zipcode;
}
...
My Controller class
public class ZipCodesController : Controller
{
private MyContext db = new MyContext();
//
// GET: /ZipCodes/
public ActionResult Index()
{
var zipcodes = db.ZipCodes.Include(z => z.State);
return View(zipcodes.ToList());
}
//
// GET: /ZipCodes/Details/5
public ActionResult Details(int id = 0)
{
ZipCode zipcode = db.ZipCodes.Find(id);
if (zipcode == null)
{
return HttpNotFound();
}
return View(zipcode);
}
...
I dont undersatnd the point where you are showing the MVC Contoller.Am i missing something there? However For Webapi (ApiController) You can re write your Method as follows. This should pass the enitre Object in one response.
public HttpResponseMessage GetZipCode(int id)
{
ZipCode zipcode = db.ZipCodes.Find(id);
if (zipcode == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound)
}
return Request.CreateResponse(HttpStatusCode.OK,zipcode);
}
Sending Binary Images. You need to set Straemcontent and content-type. I found a link that can help you with that Images with Webapi . Look through the entire thread . You might figure out quickly whats missing...

Reuse model data in a post action

In my viewmodel, I have a list of items I fetch from the database and then send to the view. I would like to know if it's possible to avoid having to refill the options property whenever I hit a Post action and need to return the model (for validation errors and what not)?
In webforms, this wouldn't be necessary.
Edit: I was not clear. My problem is with the SelectList options I use for my DropDownLists. Everything gets posted, but if I have to return to the view (model is invalid), I have to reload the options from the database! I want to know if this can be avoided.
My viewmodel:
public class TestModel
{
public TestModel()
{
Departments = new List<SelectListItem>();
}
public string Name { get; set; }
public int Department { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
}
My view:
#model MvcApplication1.Models.TestModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Name)
#Html.DropDownListFor(m => m.Department, Model.Departments)
<input type=submit value=Submit />
}
My controller (do notice the comment on HttpPost):
public ActionResult Index()
{
TestModel model = new TestModel
{
Name = "Rafael",
Department = 1,
Departments = new List<SelectListItem>
{
new SelectListItem { Text = "Sales", Value = "1" },
new SelectListItem { Text = "Marketing", Value = "2", Selected = true },
new SelectListItem { Text = "Development", Value = "3" }
}
};
// Departments gets filled from a database.
return View(model);
}
[HttpPost]
public ActionResult Index(TestModel model)
{
if (!ModelState.IsValid)
{
//Do I have to fill model.Departments again!?!?!?
return View(model);
}
else { ... }
}
Thanks in advance.
Edit: FYI, my solution was to use the Session variable.
Just need to strongly type your view, and change your controller method to have a parameter of that class type.
That is, the view
#model MyNamesspace.Models.MyModel
...
#using (Html.BeginForm())
{
....
}
And you controller method which is posted to.
[HttpPost]
public ActionResult MyAction(MyModel model)
{
...
}
EDIT: Also make sure you have form fields for each property of the model which you need posted to the controller. My example is using Razor too BTW.
I encountered a similar problem when trying to create an Order wizard in MVC (one where each page of the wizard is implemented as a partial view loaded by AJAX). I highly doubt it is the suggested method but my way of solving this was to call a custom MergeChanges method in each action called by my wizard:
public Order MergeChanges(Order newOrder)
{
var sessionHistory = (List<string>)Session["sessionHistory"];
if (sessionHistory == null || sessionHistory.Count == 0)
return MergeChanges(newOrder, -1);
return MergeChanges(newOrder, MasterViewController.GetStepNumberByName(sessionHistory.Last()));
}
public Order MergeChanges(Order newOrder, int step)
{
PreMerge(newOrder);
Order result = null;
try
{
ApplyLookups(ref newOrder);
Order oldOrder = (Order)Session["order"];
if (oldOrder == null)
{
Session["order"] = newOrder;
result = newOrder;
}
else
{
List<TypeHelper.DecoratedProperty<ModelPageAttribute>> props = null;
newOrder.GetType().GetDecoratedProperty<ModelPageAttribute>(ref props);
props = props.Where(p => (p.Attributes.Count() > 0 && p.Attributes.First().PageNumber.Contains(step))).ToList();
foreach (var propPair in props)
{
object oldObj = oldOrder;
object newObj = newOrder;
if (!string.IsNullOrEmpty(propPair.PropertyPath))
{
bool badProp = false;
foreach (string propStr in propPair.PropertyPath.Split('\\'))
{
var prop = oldObj.GetType().GetProperty(propStr);
if (prop == null)
{
badProp = true;
break;
}
oldObj = prop.GetValue(oldObj, BindingFlags.GetProperty, null, null, null);
newObj = prop.GetValue(newObj, BindingFlags.GetProperty, null, null, null);
}
if (badProp)
continue;
}
if (newObj == null)
continue;
var srcVal = propPair.Property.GetValue(newObj, BindingFlags.GetProperty, null, null, null);
var dstVal = propPair.Property.GetValue(oldObj, BindingFlags.GetProperty, null, null, null);
var mergeHelperAttr = propPair.Property.GetAttribute<MergeHelperAttribute>();
if (mergeHelperAttr == null)
{
if (newObj != null)
propPair.Property.SetValue(oldObj, srcVal, BindingFlags.SetProperty, null, null, null);
}
else
{
var mergeHelper = (IMergeHelper)Activator.CreateInstance(mergeHelperAttr.HelperType);
if (mergeHelper == null)
continue;
mergeHelper.Merge(context, HttpContext.Request, newObj, propPair.Property, srcVal, oldObj, propPair.Property, dstVal);
}
}
result = oldOrder;
}
}
finally
{
PostMerge(result);
}
return result;
}
Since my case was doing this with a wizard, only specific values applied to each page so in order to only account for properties known to the current page of the wizard, I've implemented some attributes, a (admittedly over complex) ViewController layer, and a custom validation layer. I can share some more code but the code above does the grunt work if you aren't in such a complex situation. If there is a better way, I hope to learn it from the answers to this question because this was a PITA.
I am surprised this question doesn't come up more often, and I am also surprised the obvious (IMHO) answer isn't standard practice these days: nearly all POSTs should be Ajax-based. This solves a whole slew of problems including
No need to repopulate form data when you have e.g. a validation error, or application error (exception). This is particularly desirable when you have client-side state (in true rich web application fashion).
No compulsion to perform client-side validation. Validation can be 100% server-side (where it must be anyways) and the user experience is nearly the same.
Of course, there is some initial work you need to do to build out a framework for this, for example, I have a set of AjaxUpdate, AjaxNothing, AjaxRedirect, AjaxErrors ... ActionResult types which render Json which is processed by some custom Javascript. But once you get that in place, it's smooth sailing.

Categories