I am new to asp.net, what I really want is to give a parameter to an ActionResult.
I want somtehing like this (I dont know if this is possible)
Sudoku s = new Sudoku();
// SudokuClass has a property -> public int[,] MyFields {get;set;}
public ActionResult Index(int value)
{
if(value == 1)
{
myGame.Create();
s.MyFields = myGame.GameField();
}
if(value == 2)
{
myGame.Cheat();
s.MyFields = myGame.GameField();
}
if(value == 3)
// some code
return View(s);
}
MyCode is Index.cshtml
#Html.ActionLink("Cheat", "Index")
What i want is: if I click on the actionlink "Cheat", that i can give number 2 so the Cheat Method will start, and update s.MyFields;
The other code for displaying the fields I have omitted. I can get the fields show on the webpage when I use s.MyFields = mygame.GetFields(). So thats not the problem, the problem is how can I "Update" this when I Click on cheat.
#Html.ActionLink("Cheat", "Index", new { value = 2})
Or any number you want to pass from your View.
Related
I have a form in a view in a C# ASP.NET MVC project that due to a bug in an earlier js cropping module occasionally ends off having a minus 1 (-1) in the value of the 'CropY' field.
Rather than trying to debug the cropper I thought I could just check for the -1 and make it a zero in the view, here:
#model UI.Models.PVModel
...
#Html.HiddenFor(x => x.CropY)
However, I don't seem to be able to modify the HiddenFor to set a value or 0 depending on if the value is >-1 or not, say with
#Html.HiddenFor(x => (x.CropY < 0 ? 0 : x.CropY))
As this (and all other combos I tried) gives me an error ( 'Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.').
I tried altering the model value itself before the form on the view with
model.CropY = (model.CropY < 0 ? 0 : model.CropY)
But that doesn't alter the value in the HiddenFor form field (I'm a beginner to C# and .NET so forgive me if this is a fundamental error)
Next I tried altering the model itself to test for this
public int CropY
{
set { CropY = value; }
get { return (CropY < 0 ? 0 : CropY); }
}
But I can't get this to work (System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.'), even if it is a viable method and I confess I don't know the correct format here!
Any idea please? Thanks.
--- edit after discussions below, this is more of what has been tried ---
Thanks. Okay, So very similarly, I have a basic get;set; in my model:
public class ProductViewModel
{
public int CropY { get; set; }
Then in my controller, it's a post as it's x in y number of forms/pages that go one after another:
[HttpPost]
[Route("Edit")]
[ValidateAntiForgeryToken]
public ActionResult Edit(ProductViewModel model, string nav)
{
model.CropY = (model.CropY < 0 ? 0 : model.CropY)
...
return View(view, model);
}
Then in my view I have this:
#model edie.UI.Models.ProductViewModel
#{
ViewBag.Title = "Step 2/";
}
<form action="#Url.Action(null, "MyPages")" method="post" class="form" novalidate="novalidate">
#Html.AntiForgeryToken()
#Html.HiddenFor(x => x.CropY)
And the value, when I view the page, is still coming through as -1. If I set breakpoints and step the code and check I can see the line in the controller is being triggered and setting CropY to 0, and the view is returned. On the view itself I can see the Model.CropY is 0. But the HiddenFor(x => x.CropY) inserts -1!
I suppose I'm missing something...
I would personally avoid implementation of setters and getters in Model/ViewModel objects, of course, it can helps in special cases but let's keep it simple. So, first of all, i would create simple view model object like this:
public class IndexViewModel
{
public int CropY { get; set; }
}
I would move the business logic from the view to the controller. In perfect world it should be moved to some service (SOC). So my get method in the home controller would look like this:
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
var value = -2;
var viewModel = new IndexViewModel();
if(value < 0)
{
viewModel.CropY = 0;
}
else
{
viewModel.CropY = value;
}
return View(viewModel);
}
}
And the Index.cshtml:
#model WebApplication1.Models.Home.IndexViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.HiddenFor(x => x.CropY)
value = -2; it's a variable which stores value that you receives (I suppose) from some data source like repository.
After some help from #stephen-muecke I found an answer. The issue is with with the modelstate. See TextBoxFor displaying initial value, not the value updated from code and TextBoxFor displaying initial value, not the value updated from code
So two of the methods I tried above did actually work (in a way) - altering the get; set; to handle the negative value and adding a check and update of the value in the controller before I return the view.
In the view itself the Model.CropY contained the correct 0 value then but the #Html.HiddenFor(x => x.CropY) still had the bad -1 value, and so added it to the form.
So the helper HiddenFor helper gets its value from the ModelState value, and not the model I was trying to alter and edit on the view.
Confused? I still am, but adding this in my POST controller fixed it:
ModelState.Clear();
You can also do a ModelState.Remove("SomeText"), so I'm advised this might be a better option that clearing the entire modelstate.
I have a controller named (Term1score) and inside the controller i have two different action method(Index_Test,EditScore).
Now inside the view of my (Index_Test)i have Html action-link that will redirect to (Edit Score)now what i want is it will redirect to the specific Id (Example if(Index_Test) SubjectId=1 then it will go to(EditScore) SubjectID=1,)as u can see in my Controller they both target same SubjectID,any idea on how to fix this? thanks and appreciate your response..
Controller:
public ActionResult Index_Test(int? id)
{
List<Term1Score> score = db.Term1Scores.Where(x => x.SubjectID == id).ToList();
return View(score);
}
[HttpGet]
public ActionResult EditScore(int? id)
{
List<Term1Score> score = db.Term1Scores.Where(x => x.SubjectID== id).ToList();
return View(score);
}
I have tried to put this inside the Index_Test View.
This One Work but it will always go to Id 1 only-How to make this automatic changed?
#Html.ActionLink("Edit", "EditScore", "Term1Score", new { id= "1" }, null
I have tried few but still nothing.
#Html.ActionLink("Edit", "EditScore", "Term1Score", new { id=#Model.id }, null)
#Html.ActionLink("Edit", "EditScore", "Term1Score", new { testId=testId.id }, null)
#Html.ActionLink("Edit", "EditScore", "Term1Score", new { id= "" }, null)
EDIT : As per the comment
i'm targeting one link to edit all now with the code u gave its
looping one by one, and Editscore is a Multi editable table
In this case, You can get the first item and use it's SubjectID
#model List<Term1Score>
#{
var id = Model.FirstOrDefault() != null ? Model.First().SubjectId : (int?) null;
}
#Html.ActionLink("Edit", "EditScore", "Home", new { id = id }, null)
Another option is create a view model which has 2 properties, one for the Id and one for the List of Term1Score and use that to transfer data to your view.
Your Index_Test action method is passing a list of Term1Score objects to the view, So you need to loop through them and render a edit link
The EditScore action method parameter name is id. So make sure when you are building the anchor tag using Html.ActionLink helper, you use id as the route value object key.
So in your Index_Test.cshtml
#model List<Term1Score>
#foreach (var testId in Model)
{
<p>
#Html.ActionLink("Edit", "EditScore", "Home", new { id = testId.Id }, null)
</p>
}
Also , in the EditScore method, you probably want to edit a single record, Currently you are returning the same collection as the previous method. You probably want to get the single record matching that id.
[HttpGet]
public ActionResult EditScore(int id)
{
Term1Score score = db.Term1Scores.FirstOrDefault(x => x.Id== id);
if(score==null)
{
return Content(" This item does not exist"); // or a view with the message
}
return View(score);
}
Now since you are passing a single item, make sure your view is strongly typed to that
#model Term1Score
<h2>#Model.Id</h2>
I'm running asp.net 4 mvc and I've created a DropDownList of dates that defaults to the first entry in the list. When I select an entry, I invoke a controller function and do some processing. However, when my page does the PostBack, instead of displaying the list item I selected, it displays the original default list item again.
How do I get my page to display the last item I selected from the list? I've spent two full days searching this site and the Internet for a solution but nothing I try seems to work. Any assistance would be greatly appreciated.
My Html View
#Html.DropDownList("selectList", Model.ReverseMonthsLists(),
new { #onchange = "CallChangefunc(this.value)" })
<script>
function CallChangefunc(val) {
window.location.href = "/dashboard/Report_Performance?id=" + val;
}
</script>
My ViewModel
public SelectList MonthList { get; set; }
public IEnumerable<SelectListItem> ReverseMonthsLists()
{
var selectListItems = GetDates()
.Select(_ => _.ToString("MMM yyyy"))
.Select((dateString, index) => new SelectListItem { Selected = index == 0, Text = dateString, Value = dateString })
.ToList();
return selectListItems;
}
public static IEnumerable<DateTime> GetDates()
{
DateTime startDate = new DateTime(2017, 6, 1).Date;
var currentDate = DateTime.Now.Date;
int numberOfMonthsToShow = (currentDate.Year - startDate.Year) * 12 + currentDate.Month - startDate.Month;
var dates = new List<DateTime>(numberOfMonthsToShow);
currentDate = currentDate.AddMonths(-1);
for (int i = 0; i < numberOfMonthsToShow; i++)
{
dates.Add(currentDate);
currentDate = currentDate.AddMonths(-1);
}
return dates;
}
My Controller
[RequireLogin]
public ActionResult Report_Performance(string id)
{
DateTime newDate = DateTime.Now.Date.AddMonths(-1);
if (id != null)
newDate = DateTime.Parse(id);
var aVar = Models.Reporting.ListingStatsReportingViewModel.GetStats(userCurrentService.CompanyId.Value, Models.Reporting.DateTimePeriod.Monthly, newDate);
return this.View(aVar);
}
You can change your code as follows:
Let's say your model class that is being returned by GetStats method in the Report_Performance action is MyStats which contains a string property named SelectedDateString (you need to add this property to your view model class).
Updated view markup:
#model MyStats
#Html.DropDownList("SelectedDateString", Model.ReverseMonthsLists(),
new { #onchange = "CallChangefunc(this.value)" })
<script>
function CallChangefunc(val) {
window.location.href = "/dashboard/Report_Performance?id=" + val;
}
</script>
Updated controller:
[RequireLogin]
public ActionResult Report_Performance(string id)
{
DateTime newDate = DateTime.Now.Date.AddMonths(-1);
if (id != null)
newDate = DateTime.Parse(id);
var aVar = Models.Reporting.ListingStatsReportingViewModel.GetStats(userCurrentService.CompanyId.Value, Models.Reporting.DateTimePeriod.Monthly, newDate);
//This will make sure that the model returns the correct value of the property as a string.
aVar.SelectedDateString = id;
return this.View(aVar);
}
A Html.DropDownList() works by getting data from a string property in the model which is of the same name as the name of the DropDownList itself.
In your case, you need to set the DropDownList value using javascript or jquery as it's not connected to a model property.
Let me give you an example:
A drop down list in MVC can be created by using either
#Html.DropDownListFor(m => m.PreferredContactMethod, Model.PreferredContactMethods, "")
or
#Html.DropDownList("PreferredContactMethod", Model.PreferredContactMethods, "")
In both cases, PreferredContactMethod is a string property in my model that is connected to the view - which is done by specifying #model PreferredContactModel at the top of the view.
In your case, your list name is selectList and if the specified model is connected to the view and if there's a property in the model that gets the selected date, then you need to change the name of your drop down list to it.
I hope it makes sense, if there's any issue, please comment back. I want to help with this.
The problem is here:
window.location.href = "/dashboard/Report_Performance?id=" + val;
This essential tells the browser to navigate to a new page, which is an HttpGet operation. Thus, there is no correlation between your current settings and those of a new page.
It's as if you had just gone up to the address bar and hit enter. It issues a new page with all new defaults.
There are many ways you can address this problem. The easiest would be to have some javascript that looks at the URL and extracts the id query parameter, then selects the item in the dropdown box that corresponds with the id.
Another option is to set the dropdownlist's selected value based on the ID in your controller.
In controller:
ViewBag.SelectedItem = id;
In View:
#Html.DropDownList("SelectedItem", Model.ReverseMonthsLists(), ...)
Here is my logic in a code snippet.
I am trying to login, if data comes from web-page and if it matches with the database to proceed allowing to login
[HttpPost]//post method
public ActionResult Index(FormCollection collection)//using formcollection
{
var logindata = amcs.Logins.Where(a => a.Admin_Email_Id == collection["Admin_Email_Id"] && a.Admin_Password == collection["Admin_Password"]).SingleOrDefault();//compare string
if (logindata == null)//match data
{
return Redirect("/Contract/Login/index");//redirect if not match
}
else
{
Session["Emailids"] = collection["EmailId"];//add session
Session["Passwords"] = collection["AdminPassword"];
return Redirect("/Contract/Homepage/index");
}
}
If you are getting NULL as a result, have you looked further into this yourself?
For example, what values are
collection["Admin_Email_Id"]
collection["Admin_Password"]
Does the data in amcs.Logins contain objects whose properties match those values? You can hover the mouse of the data and look at it in the debugger.
EDIT
In response to a comment:
In the HTML does the
<input type="text" id="Admin_Email_Id"> also have an attribute name="Admin_Email_Id"? If not then add it manually e.g.
Html.TextBoxFor(m => m.Admin_Email_Id, new { name = "Admin_Email_Id", PlaceHolder = "EmailId"})
I'd be surprised that you need to do that though, but it's worth checking the HTML to check that name is there. Without name, when posting to the controller, the FormColleciton won't have a value for that missing name
I'm creating a question/answer page that contains multiple object types (radio button, dropdown, check boxes).
Id QuestionText AnswerId AnswerText ObjectType
1 text one 1 Personal DropDown
1 text two 2 Business DropDown
2 Text three 3 Direct Deposit CheckBox
2 text four 4 Some Answer CheckBox
I have a model that contains a list of all questions, answers, and object types.
How can I populate (as an example) the dropdownlistfor with only two items out of the list, then populate a group of related checkboxes, then populate a group of related radio buttons?
The dropdownlistfor looks to enumerate on a model.
My code which doesn't work:
#if (Model != null)
{
for (int i = 0; i < Model.Count; i++)
{
if (Model[i].AdditionalQuestionTypeId == 1)
{
#Html.DropDownListFor(model => model[i].AdditionalQuestionId, ((IEnumerable<Curo.Web.InterAcct.Models.AdditionalQuestionAnswerModel>)Model[i].AnswerText)
.Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Description),
Value = option.Id.ToString(),
Selected = (Model != null) && (option.Id == Model[i].AdditionalQuestionId)
}), "Choose...")
It's not the best idea to clog up your view with a bunch of logic. That is actually not the desired approach of MVC.
Use this logic in your controller and not the View.
Create you options in the controller that you want for the desired scenario and set the options to the property on the Model. Then your view will simply bind to that property.
public class MyModel {
public string MyValue { get; set;}
public List<SelectListItem> Options { get; set; }
}
public ActionResult MyAction(){
MyModel model = new MyModel();
// populate options here
model.Options = new List<SelectListItem>();
return View(model);
}
Then your view:
#Html.DropDownListFor(m => m.MyValue, m => m.Options)
It's hard to tell from your code, but I think you are almost there. You need to do the dropdownlistfor statement with an IEnumerable, but your syntax appears to be off:
#Html.DropDownListFor(model => model[i].AdditionalQuestionId, new SelectList(Model.Answers.Where(f=>**Some code to select what values you want**), "Id", "Description", Model[i].AdditionalQuestionId))
It would help to see an error message, but I think it is just syntax at this point.