Incrementing and Decrementing a querystring parameter? - c#

In my current MVC project(the third question I've asked on this same project!), I have a 'Landing Page' which after one click of a button redirects to the following page URL:
localhost:111111/AccountsFinance/Index?questionId=1
I can edit the URL manually and change Id=2 which does change what is displayed, but I need a button to do this of course.
Within this View, I have the following:
#using (Html.BeginForm("Index", "AccountsFinance", FormMethod.Post))
{
//SOME CODE
<input class="btn btn-success" type="submit" value="Back" />
<input class="btn btn-success" type="submit" value="Next" />
}
Here is my controller code, not sure if it is necessary for this question but better to include it than not to!
public AccountsFinanceQuestion afqList = new AccountsFinanceQuestion();
public ActionResult Index(string ans)
{
int qId = int.Parse(Request.QueryString["questionId"]);
using (S3WEntities1 ent = new S3WEntities1())
{
afqList.Question = ent.Questions.Where(w => w.QuQuestionId == qId).Select(s => s.QuQuestion).FirstOrDefault().ToString();
afqList.Answers = ent.Answers.Where(w => w.AnsQuestionId == qId).Select(s => s.AnsAnswer).ToList();
}
return View("Index", afqList);
}
So how would I increment/decrement the questionId=X part of the query string so that it moves on to the next question/the previous question. This is all in the same view on the same method on the same controller. I also understand that this may not work so well for the very first question if the user clicks back, as the URL is completely different, but that is something to come on to at a later date.

First of all, you don't need to parse query string parameters manually - default binder will do it for you. Just define method parameter with corresponding name. E.g.
public ActionResult Index(int questionId)
Second, seems like you are reviewing details of some question. So I don't think that Index is appropriate action for that. I suggest to use Details or Edit:
public ActionResult Details(int questionId)
And regarding links to next and previous questions - you can just generate action links in your view:
#Html.ActionLink("Back", "Details", new { questionId = Model.QuQuestionId - 1 }
#Html.ActionLink("Next", "Details", new { questionId = Model.QuQuestionId + 1 })
Also note, that your approach has several problems:
What if some question was deleted and ids are not incremental anymore?
What if current question has id = 1, i.e. it's a first question? It should not have link to previous question
What if current questions is last one?
Easiest way to solve these problems - pass ids of previous and next questions to your view. You can use model properties for that, or you can use ViewBag:
ViewBag.PrevQuestionId = ent.Questions
.Where(q => q.QuQuestionId < questionId)
.OrderByDescending(q => q.QuQuestionId)
.Select(q => q.QuQuestionId)
.FirstOrDefault();
Then in View you can conditionally add link to previous question:
#if (ViewBag.PrevQuestionId > 0) {
#Html.ActionLink("Back", "Details", new { questionId = ViewBag.PrevQuestionId }
}
Same with next question

You can do something like this in your controller:
int qId = int.Parse(Request.QueryString["questionId"]);
Response.RedirectToRoute("current-route?questionId=" + qId++);

Related

Form not returning value to controller action due to ID conflict

I have a form with a DropDownListFor. When I select the ID from my drop down list, select a date and click submit, I get error:
The parameters dictionary contains a null entry for parameter 'CasinoID' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Index(Int32, System.DateTime, NameSpace.ViewModels.TerminalReceiptPostData)' in 'Namesppace.Controllers.TerminalReceiptsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
It worked fine with just a regular Input tag and typing it in manually... however when I added a DropDownListFor this issue arises. Am I setting up the DDL wrong? Any other issues as to why this would happen? Below is some code.
Controller Action:
[HttpPost]
public ActionResult Index(int CasinoID, DateTime Date)
{
var model = TRBL.GetTransactionTestsData(CasinoID, Date);
return View(model);
}
View:
#using (Html.BeginForm("Index", "TerminalReceipts", new { id = "submitForm" }))
{
<div>
#*<input type="text" name="CasinoID" placeholder="Enter Casino ID" id="cIdSearch" />*#
#Html.DropDownListFor(o => o.TerminalReceiptPostData.CasinoIdDDL, Model.TerminalReceiptPostData.CasinoIdDDL, new { id = "CasinoID"})
<input id="datepicker" class="datepicker-base" name="Date" placeholder="MM/DD/YYY" type="text" />
<button type="submit" class="btn btn-sm btn-primary" id="search" onclick="checkField()"> Search Transactions</button>
</div>
}
Edit update
So I was able to change how the structure a bit to now be able to get the CasinoID to be passed properly to the controller action. Below are the changes... however after the action goes to return the model, I get an obj reference not set to instance of the obj err.
Action:
[HttpPost]
public ActionResult Index(int CasinoID, DateTime Date)
{
var id = Int32.Parse(Request.Form["CasinoID"].ToString());
var model = TRBL.GetTransactionTestsData(id, Date);
return View(model);
}
Change to DDL:
#Html.DropDownList("CasinoID", Model.TerminalReceiptPostData.CasinoIdDDL, "Select Casino")
The int CasinoID will be bound by a form field with the name CasinoID. I think the #Html.DropDownListFor is not generating the 'name' you want.
You can add name explicitly like
#Html.DropDownListFor(o => o.TerminalReceiptPostData.CasinoIdDDL, Model.TerminalReceiptPostData.CasinoIdDDL, new { id = "CasinoID", name="CasinoID"})
Or better to create a ViewModel with the fields CasinoID, Date & CId and use BindProperty on that ViewModel instance
Okay so I figured out what was going on..
I actually have two seperate controller actions named Index. One for post and one for get. Since I am now sending back a model on the POST one, the drop down list was not getting "re-filled" with the drop downs... So i simply took a call from my GET action and added it to the post..
[HttpPost]
public ActionResult Index(int CasinoID, DateTime Date)
{
var id = Int32.Parse(Request.Form["CasinoID"].ToString());
var model = TRBL.GetTransactionTestsData(id, Date);
model.TerminalReceiptPostData = TRBL.GetCasinosDDL();
return View(model);
}
Probably not the best way to do it, but works fine.

asp net. How to remove data from a database

First I want to say I'm just starting to learn and I'm french, so please be very simple in your explanation. Just imagine you're talking to a 3 years old and I should be ok. Please don't overload me with dozens of lines of code without any explanation.
OK here's what I want to do: I have a very simple database table of article author. The table has 5 columns:
First Name, Second name, Dob, Phone Nb, Place of Birth, UserId
The userId is automatically created. I have created a form where a user would write the first name and second name (in 2 separated textboxes and I want to use that to fetch the userId in the table and use it to delete the entire line)
Here's the code for my form
model projet_clement.Models.HomeModel
<form method="post" action="~/home/SupressionAuteur">
<h3>deleting author page</h3>
<p>first name of the author to delete</p>
<input type="text" name="Nom" />
<p>second name of the author to delete</p>
<input type="text" name="Prenom" /><br />
<br />
<input type="submit" value="Delete" />
</form>
<h3>For reminder, here's a table of the author already created</h3>
<table>
<tr>
<td>Nom</td>
<td>Prenom</td>
<td>Date de naissance</td>
<td>N° de téléphone</td>
<td>Département de naissance</td>
<td>UserId</td>
</tr>
#foreach (var i in Model.UserList)
{
<tr>
<td>#i.Nom</td>
<td>#i.Prenom</td>
<td>#i.Naissance</td>
<td>#i.Numero</td>
<td>#i.Departement</td>
<td>#i.userId</td>
</tr>
}
</table>
OK now what I would like to know is how can I get the userId thanks to the first name and second name, and how can I delete a whole row just using this id.
Here's my c# code
[HttpGet]
public ActionResult SupressionAuteur()
{
var allUsers = db.Users.Where(x => x.Nom != null);
var model = new HomeModel(allUsers);
return View(model);
}
[HttpPost]
public ActionResult SupressionAuteur(Users formUser)
{
//for those who skipped french class, nom = first name and prenom = second name;)
var userId = db.Users.Where(x => x.Nom == formUser.Nom && x.prenom == formuser.prenom);
db.Users.Remove([What should i write here?]);
return RedirectToAction("SupressionAuteur", "Home");
}
Of course it doesn't work!
When I run my code the userId var never get the good value. So I guess the way I try to get it is wrong
And how am I supposed to use the db.users.remove() method? Is it the one I should use by the way? I was told so.
Thanks in advance, I'm really stuck :)
Steps
Get the user - ideally you want to use the userid (or primary key) to retrieve the user
Remove the user from the db
Save the changes in the context
Code:
var user = db.Users.Single(x => x.Nom == formUser.Nom && x.prenom == formuser.prenom);
db.Users.Remove(user);
db.SaveChanges();

Unable to submit List of model in MVC [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 7 years ago.
I am displaying a list of items in a Collection in edit mode in a view. after editing the documents, I want to submit. But I am unable to postback the list. List shows null.
here is my View
#model List<NewsLetter.Models.NewsLetterQuestions>
#using (Html.BeginForm("GetAnswersfromUser", "NewsLetter", FormMethod.Post, null))
{
#Html.AntiForgeryToken()
foreach (var item in Model) {
<div>
#Html.DisplayFor(modelItem => item.Question)
</div>
<div>
#Html.TextAreaFor(modelItem => item.Answer)
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Submit" class="btn btn-default" />
</div>
</div>
}
Here is my Controller
public ActionResult GetAnswersfromUser(string id)
{
id = "56c5afc9afb23c2df08dd2bf";
List<NewsLetterQuestions> questions = new List<NewsLetterQuestions>();
var ques = context.NewsLetterQuestionCollection.Find(Query.EQ("NewsLetterId", id));
foreach(var x in ques)
{
questions.Add(x);
}
return PartialView(questions);
}
[HttpPost]
public ActionResult GetAnswersfromUser(List<NewsLetterQuestions> nql)
{
string id = "56c5afc9afb23c2df08dd2bf";
foreach (var item in nql)
{
var query = Query.And(Query.EQ("NewsLetterId", id), Query.EQ("Question", item.Question));
var update=Update<NewsLetterQuestions>
.Set(r => r.Answer, item.Answer);
context.NewsLetterQuestionCollection.Update(query,update);
}
return RedirectToAction("NewsLetterIndex");
}
When i hit submit it throws error.
System.NullReferenceException: Object reference not set to an instance of an object.
In the line
foreach (var item in nql)
which means that nql is null.
In order for the model binder to be able to bind the posted data, all your input names need to be in the format of [N].Property, where N is the index of the item within the list. In order for Razor to generate the input names properly, then, you need to pass it an indexed item, which means you need a for loop, rather than a foreach:
#for (var i = 0; i < Model.Count(); i++)
{
...
#Html.TextAreaFor(m => m[i].Answer)
...
}
You're never passing the list back to the controller's Post handler. You need to route the list back to the controller.
You should be doing something similar to this untested code :)
Html.BeginForm("Index", "Home", new { #nql=Model }, FormMethod.Post)
Take a look at this post as well. It is similar to your issue: Pass multiple parameters in Html.BeginForm MVC4 controller action and this Pass multiple parameters in Html.BeginForm MVC

C# MVC Query with WHERE clause and 2 params from the View

I need to query my database with a WHERE clause and pass to parameters from my view to the controller. I am at a total loss as I am a JavaScript and PHP developer and am currently learning dotnet MVC (I am using vs10 framework4).
I need to in essence make this query:
select * from myTable where column1=16 and column2=24
The values of column1 and column2 are in my View. I have found a million examples on how to pull either a whole table, or a result based upon one parameter, I cannot figure out how to do that simple query.
This seems like a simple task and I would appreciate any help as I have spent 5 hours trying to figure this out.
Here are some key components of my code that will hopefully help someone help me. I sincerely appreciate any help.
Controller:
public class SignBuilderController : Controller
{
SignBuilderModel signBuilderModel = new SignBuilderModel();
//
// Initialize database entities
SignBuilderEntities _db;
public SignBuilderController()
{
_db = new SignBuilderEntities();
}
//
// Get /SignBuilder/PrintSetup
[Authorize]
public ActionResult PrintSetup()
{
var pricesList = signBuilderModel.GetPricingList().ToList();
return View("PrintSetup", pricesList);
}
// get Column1 and column 2 query
public ActionResult TestPage(int column1, int column1)
{
//do something here
return View();
}
And in my View I would retrieve the values for my where clause from input fields.
Example:
<input type="text" name="column1value" id="column1value" />
<input type="text" name="column2value" id="column2value" />
Obviously I am using a Model as well, so if that is needed to make this work no problem. I am really looking for sample code I can use as an example to learn from. I really appreciate any help, and am about to pull out my hair.
Try this(I assume your view is strongly typed):
public ActionResult(int column1, int column2)
{
//do something here.
var model =
(
from p in this.GetPricingList()
where (p.column1 == column1) && (p.column2 == column2)
select p
).FirstOrDefault();
return View(model);
}
and in the View:
<input type="text" name="column1" id="column1value" value="<%=Model.column1%>"/>
<input type="text" name="column2" id="column2value" value="<%=Model.column2%>"/>
You need to post the values to the Action method on your controller
Using something like this in your view:
<% using (Html.BeginForm("RunQuery", "ControllerName")) { %>
<input type="text" name="column1" id="column1value" />
<input type="text" name="column2" id="column2value" />
<input type="submit" value="Run Query" />
<% } %>
and then the accompanying action method
[HttpPost]
public ActionResult RunQuery(string column1, string column2)
{
var results = GetDataFromDatabase(column1, column2);
return View(results );
}
I'm afraid your code would not compile. What you annotated as your controller does not inherit from controller class at all and your actionresult method has no name. I wonder how could you visit your page in the browser. The code should be like
public class MyApplicationModel:Controller
{
//use entity framework
private MyApplicationEntities entities = new MyApplicationEntities();
//
// Method to query database for price lists table
public IQueryable<pricingUploaded> GetPricingList()
{
return entities.pricingUploadeds;
}
//
// Method to query Column1 and Column2 in table pricingUploaded
[HttpGet]
public ActionResult Query()
{
//this action will render the page the first time
return View();
}
[HttpPost]//this method will only accept posted requests
public ActionResult Query(int column1, int column2)
{
//do something here.
var _result = entities.Where(x=>x.column1 == column1 && x.column2 == column2);
return View(_result);//pass result to strongly typed view
}
In your view you have to create a form, that when submitted can post values to HttpPost overload of Query method
<%:Html.BeginForm();%>
<input type="text" name="column1">
<input type="text" name="column2">
<input type="submit" id="save" value="query">
<%:Html.EndForm();%>
Now you enter values in your form and click query button, you will have column1 and column2 values in you Query Actionresult accepting posted request. You better put a break point there and inspect how things are really working and figure out how to do what you need to do.
Edit: based on your comment that you want to pass values ajaxically you can do little bit of jQuery:
<script type="text/javascript">
$(function(){
$("form").submit(function(){
$.ajax({
type:"post",
url:"myapplicationmodel/query",
success:function(data)
{
//do something with returned data
}
});
return false;// to prevent normal form post
});
});
</script>
What about this:
public ActionResult(int column1, int column2)
{
var query = from m in _db.MyTable
where m.Column1 == column1
where m.Column2 == column2
select m;
// Or this for typed model
// select new MyModel { Column1 = m.Column1, etc }
var model = query.First();
return View(model);
}
I'm assuming that the entities is a Linq to Entity right? if that is the case, couldn't you use:
var model = from e in entities
where column1=16 and column2=24
select e;
and then pass that model into the vew.
Basically, if entities is of the type IQueryable or IEnumerable or any of the other linq-able interfaces, you can perform that type of query. Make sure that you are using System.Linq; in the top of your code file.
Hope that helps!

dropdown in mvc3 edit form

This maybe very simple but I cant seem to sort it out on my own.
I have created a simple db and entity modal that looks like this
I am trying to create an Create form that allows me to add a new Order. I have a total of 3 tables so what I am trying to do is have the form allowing the person to enter Order date and also has a dropdown list that allows me to select a product from the product table
I want to be able to create a Add or Edit view that allow me to insert the OrderDate into the OrderTable and also insert the OrderID and selected ProductID into OrderProduct.
What steps do I need to do here.
I have created an OrderController and ticked the "Add Actions" and than added a Create View which looks like this
#model Test.OrderProduct
#{
ViewBag.Title = "Create2";
}
<h2>Create2</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>OrderProduct</legend>
<div class="editor-label">
#Html.LabelFor(model => model.OrderID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OrderID)
#Html.ValidationMessageFor(model => model.OrderID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ProductID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ProductID)
#Html.ValidationMessageFor(model => model.ProductID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
This creates the view that contains a textbox for both OrderID and ProductID however no date.
My controller CreatePost hasnt been changed
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
var data = collection;
// TODO: Add insert logic here
// db.Orders.AddObject(collection);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
My questions are,
1.How do I swap out ProductID textbox to be a dropdown which is populated from Product
2.How do I get the data from FormCollection collection? I thought of just a foreach however I dont know how to get the strongly typed name
Any help for a newbie would be very helpful.
Thank you!
First thing's first, don't bind to the Order entity. Never bind to an EF object, always try and use a ViewModel. Makes life simpler for the View, and that is the goal here.
So, have a ViewModel like this:
public class CreateOrderViewModel
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public int SelectedProductId { get; set; }
public IEnumerable<SelectListItem> Products { get; set; }
}
That's it right now.
Return that to your View in your [HttpGet] controller action:
[HttpGet]
public ActionResult Create()
{
var model = new CreateOrderViewModel
{
Products = db.Products
.ToList() // this will fire a query, basically SELECT * FROM Products
.Select(x => new SelectListItem
{
Text = x.ProductName,
Value = x.ProductId
});
};
return View(model);
}
Then to render out the list of Products: (basic HTML excluded)
#model WebApplication.Models.CreateOrderViewModel
#Html.DropDownListFor(model => model.SelectedProductId, Model.Products)
The only thing i don't know how to do is bind to the DateTime field. I'm guessing you would need an extension method (HTML Helper) which renders out a Date Picker or something. For this View (creating a new order), just default to DateTime.Now.
Now, onto the [HttpPost] controller action:
[HttpPost]
public ActionResult Create(CreateOrderViewModel model)
{
try
{
// TODO: this manual stitching should be replaced with AutoMapper
var newOrder = new Order
{
OrderDate = DateTime.Now,
OrderProduct = new OrderProduct
{
ProductId = SelectedProductId
}
};
db.Orders.AddObject(newOrder);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Now, i also think your EF model needs work.
To me (in English terms), a Product can have many orders, and an Order can have many Products.
So, it should be a many-to-many. Currently it's a 1-1 with a redundant join table. Did you generate that from a DB? If so, your DB possibly needs work.
You should have a navigational property called Products on the Order entity, which references a collection of Product, made possible by a silent join to the join table in the many-to-many.
This also means you no longer have a DropDownList, but a MultiSelectDropDownList.
Thanks Craig. Your few days (as at time of posting) of MVC have solved my few days of trying to get the selected value back from DropDownListFor.
I had no problem in the Create view in getting the selected value of the DDLF, but the Edit view was a completely different matter - nothing I tried would get the selected value back in the Post. I noticed the selected value was lurking in the AttemptedValue of the ModelState, and so Dr.Google referred me here.
I had this in my view
#Html.DropDownList(model => model.ContentKeyID, Model.ContentKeys, Model.ContentKeyName)
where ContentKeys is a SelectList populated from the DB via a ViewModel, and ContentKeyName is the curently selected name.
The wierd thing is, I have another DDL on the view populated in an identical manner. This one works. Why, I don't know. It is the second DDL on the form, but I can't see that making a difference.
I read somewhere else it might have been that I was using Guids as the Id, but that didn't seem to make a difference - I changed to Int32, but don't think I had to - I think it's enums that disagree with DDLF. Nullables seemd to make no difference either.
Now that I've added the form collection to my Post ActionResult, and get the selected value using
-view
#Html.DropDownList("ContentKey", Model.ContentKeys)
-in controller (Post)
contentKeyId = int.Parse(form.GetValue("ContentKey").AttemptedValue);
all is good, and I can get on with more exciting things. Why is that the simplest things can hold you up for so long?
I have been struggling with this over the last day or so too. I'll share my limited knowledge in the hope that it will help someone else.
Note that I use a singleton with a pre-populated list to keep my example application small (i.e. no EF or DB interaction).
To show the ProductList you will need to have a ViewBag or ViewData item which contains the ProductList.
You can set this up in the Controller with something like
ViewData["ProductList"] = new SelectList(Models.MVCProduct.Instance.ProductList, "Id", "Name", 1);
Then update your View to something like:
<div class="editor-field">#Html.DropDownList("ProductList")</div>
For the Post/Create/Update step you need to look into the FormCollection to get your results. Reading other posts it sounds like there used to be a bug in here, but it's fixed now so ensure you have the latest. For my example I have a DropDownList for Product so I just get the selected Id and then go searching for that Product in my list.
[HttpPost]
public ActionResult Create(FormCollection form )//Models.MVCOrder newOrder)
{
MVC.Models.MVCOrder ord = Models.MVCOrder.Instance.CreateBlankOrder();
//Update order with simple types (e.g. Quantity)
if (TryUpdateModel<MVC.Models.MVCOrder>(ord, form.ToValueProvider()))
{
ord.Product = Models.MVCProduct.Instance.ProductList.Find(p => p.Id == int.Parse(form.GetValue("ProductList").AttemptedValue));
ord.Attribute = Models.MVCAttribute.Instance.AttributeList.Find(a => a.Id == int.Parse(form.GetValue("attributeId").AttemptedValue));
UpdateModel(ord);
return RedirectToAction("Index");
}
else
{
return View(ord);
}
}
I've only been working on MVC3 for the last few days, so any advice on improving the above would be appreciated.

Categories

Resources