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
Related
In an MVC application, I have a list of exam questions and I want to present a small number of them to the user on the same page but where each answer can be submitted separately.
So my page looks like this ....
The view code is ....
#model List<QuestionResponseVM>
#for (int i = 0; i < Model.Count(); i++)
{
using (Html.BeginForm("CheckQuestions", "Checks", FormMethod.Post, new {questResponses = Model[i] }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model[i].QuestionID)
<tr>
<td width="35%">
#Html.Raw(Model[i].QuestionText)
#Html.HiddenFor(model => model[i].QuestionText)
</td>
<td>
#Html.TextAreaFor(model => model[i].Response, new { #name = "DisplayTextEdit", #id = "DisplayTextEdit", #rows = 1, #cols = 80 })
</td>
<td width="30%">
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</div>
</td>
</tr>
}
}
My problem is I can only get data returned to the POST method for Question 1.
Here is the Controller Code ....
public class ChecksController : Controller
{
public ActionResult CheckQuestions()
{
return View(LoadQuestions());
}
// POST: Checks
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CheckQuestions(List<QuestionResponseVM> questResponses)
{
List<QuestionResponseVM> testList = new List<QuestionResponseVM>();
if (ModelState.IsValid)
{
testList = LoadQuestions(questResponses[0].QuestionID, questResponses[0].Response);
}
return View(testList);
}
private List<QuestionResponseVM> LoadQuestions (int _QuestionID = -1, string _Response = "")
{
List<QuestionResponseVM> thisList = new List<QuestionResponseVM>();
thisList.Add(new QuestionResponseVM()
{
QuestionID = 1,
QuestionText = "Question 1",
Response = (_QuestionID == 1 ? _Response : "")
});
thisList.Add(new QuestionResponseVM()
{
QuestionID = 2,
QuestionText = "Question 2",
Response = (_QuestionID == 2 ? _Response : "")
});
thisList.Add(new QuestionResponseVM()
{
QuestionID = 3,
QuestionText = "Question 3",
Response = (_QuestionID == 3 ? _Response : "")
});
return thisList;
}
}
If the Controller POST method has a parameter of QuestionResponseVM questResponses which is what I was expecting (hoping for) then null is returned from the view no matter which "Save" button is clicked.
However, if I change the parameter to a list (i.e. List<QuestionResponseVM> questResponses) then the "Save" button for Question 1 returns a list with a single item and correct data. But, any other "Save" button (e.g. Question 2 or Question 3) returns a null list.
The behaviour for scenario 1. seems counter-intuitive to me since the "Begin Form" is set to return a single model item (instance of the model) i.e. "Model[i]".
And in scenario 2., I just don't understand why it works for the first form ("Save" button) but not for the others.
I don't believe I should need to use JScript or AJAX to do this.
But clearly, I am not "connecting some dots" here.
Can someone please explain my observed behaviour and maybe give me a push in the right direction to meet this requirement.?
I would greatly appreciate any help.
Before going through your questions, I don't get what new {questResponses = Model[i] })) is doing in your forms:
using (Html.BeginForm("CheckQuestions", "Checks", FormMethod.Post, new {questResponses = Model[i] }))
{
...
}
Model[i] is a complex object. All you got there was the name of the object:
Q1: If the Controller POST method has just a single parameter
Since you're using a for loop to generate each form and inputs within the form, the name of those inputs will be in the forms of [INDEX].NAME:
By default, the model binding will bind those inputs (QuestionId, QuestionText and Response) to a matching object. QuestionResponseViewModel indeed matches that. The problem is [INDEX]. prefix.
In order for the default model binding to work, the parameter name you declare in the POST method has to be called [INDEX], i.e., [0] for the first form, [1] for the second form and so on:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CheckQuestions(QuestionResponseVM [0])
{
...
}
But you know we can't declare anything like that in C#.
The Fix for Q1
Instead of using the regular for loop, you can use foreach to generate each form. In that way, you get rid of the need for naming a parameter that's changing for each form.
Another "GOTYOU" here is that the parameter in the controller has to match the variable you declared in the for loop for each QuestionResponseViewModel:
#foreach (var qrVM in Model)
{
using(Html.BeginForm("..."))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(x => qrVM.QuestionId)
<tr>
<td>
#Html.DisplayFor(x => qrVM.QuestionId)
#Html.HiddenFor(x => qrVM.QuestionId)
</td>
...
</tr>
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CheckQuestions(QuestionResponseVM qrVM)
{
// If you name the parameter something else, it won't bind!
...
}
If you think about it, that makes sense, because you know the form will post data with keys like qrVM.QuestionId, qrVM.QuestionText back to the server. The default model binding will search for a model that has those properties and is named qrVM.
Q2: Change parameter to a list
When the first form posts back to the server, the form data in the request body will look like:
[0].RequestionId: 1
[0].RequestionText: Question 1
[0].Response: xxx
MVC model binding is still smart enough and thinks you're posting the first item of the list you declared. Hence you will see List<QuestionResponseVM> questResponses capture the correct data for the first form.
Well what about the second and third form? If you submit the data on the second form for example, the form data in the request body will look like:
[1].RequestionId: 2
[1].RequestionText: Question 2
[1].Response: xxx
MVC model binding sees it as the 2nd item of the list, but where's the 1st item? And it got confused so it couldn't bind the data to the parameter. Hence you will see NULL from the parameter List<QuestionResponseVM> questResponses.
My 2 cents
You actually cannot put a form inside a table or between table rows like this. It's considered as invalid HTML structure. It's never a good idea to use tables as structures to display data on the page anyway. Instead, You can use Bootstrap's row and columns.
I don't know why or what made you think you shouldn't need AJAX. Your case is like the best scenario to go with an AJAX approach! For example, with AJAX, the user can save each question's response individually. The page doesn't have to be refreshed.
Your save button on Question 1 is submitting the form to the controller. You will need to either have one Save/Submit button at the end of a set of questions and utilize the FormCollection object or spend time setting up JQuery/Ajax for click events on each button and removing the form element. You could have a bit of both if the button at the bottom becomes a 'Next' and then submits to a controller to get the next set of related questions.
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.
var links = new List<GeckoElement>();
foreach (var link in geckoWebBrowser1.Document.Links)
{
if (!String.IsNullOrEmpty(link.GetAttribute("href").ToString()))
links.Add(link);
}
}
I have this code to collect all links in the page, but I cant figure it out how can I filter to some specific links that starts with for example "ow.ly". Rest in the list should be ignored.
Tryed this but didnt seem to work
if (links.Count > 0)
{
if (links.Equals("ow.ly"))
{
}
}
When I debug if links equals ow.ly it shows 0 reults.
links is a a List<GeckoElement>. So it’s unlikely that the list equals to the string "ow.ly". Instead, you want to filter the list for items, which href property contains that text.
You could do that for example like this:
var owlyLinks = geckoWebBrowser1.Document.Links.Where(link =>
{
string hrefAttribute = link.GetAttribute("href").ToString();
return !string.IsNullOrEmpty(hrefAttribute) && hrefAttribute.Contains("ow.ly");
}).ToList();
You might want to adjust the check so that "ow.ly" needs to appear somewhere special instead of just somewhere inside the string. For example, you could parse the whole Url, and then check that the host name equals to ow.ly.
I know there's a lot of these kind of post but I wasn't able to find any that suited me. I don't have knowledge of ajax and jquery (in fact I've just started with MVC and ASP.NET) so I need your help in this little thing.
There must be almost everywhere this kind of silly thing, I want to write a city name in a combobox, dropdownlist (or whatever) and using a method that I've already created which returns a list of locations (city, country and state names) that match the entered city. I want it to be dinamyc that's why I thought AJAX would solve this (but any other solution is accepted)
I found this jQuery autocomplete but I don't understand where to implement it. I want the combobox to match the bootstrap theme. Could someone tell me if this is an appropiate solution and if so where do I put the ajax content and else? (by where I mean, is it in the view, or controller or where?)
Or you could give mi a hint here is the method I've created for getting the elements from the database:
public List<LocationsViewModel> GetHeadquarter(string query)
{
var context = new HeadquarterContext();
//var city = context.Cities.Where(p => p.Name == query).Single();
//var province = context.Provinces.Where(p => p.ProvinceID == city.Province).ToList();
//foreach(Province prov in province) {
//}
var hq =
from c in context.Cities
join p in context.Provinces on c.Province equals p.ProvinceID
join co in context.Countries on p.Country equals co.CountryID
where c.Name == query
select new { country = co.Name, province = p.Name, city = c.Name };
List<LocationsViewModel> listLocation = new List<LocationsViewModel>();
foreach (var hqe in hq)
{
LocationsViewModel loc = new LocationsViewModel();
loc.City = hqe.city;
loc.Country = hqe.country;
loc.Province = hqe.province;
listLocation.Add(loc);
}
return listLocation;
}
Lets see if we can get it to work.
View:
This is added in your view, #Url.Action(Action, Controller) is the Action that is the source for the autocomplete function.
<input type="search" class="form-control ui-autocomplete"
data-autocomplete="#Url.Action("Autocomplete", "Home")" />
Controller (Home):
As you can see the Action Autocomplete was used to search for a product. I have an instance of my database entity called '_db' and have select a table called 'product_data' (can also use a Stored Procedure). I'm using LINQ to query the datasource and store it in the variable 'model', so it's querying where the 'term' StartsWith what is typed in the textbox, it takes the top 10 and for each one it add label and product. [{"label":value}]
public ActionResult Autocomplete(string term)
{
try
{
var model = _db.product_data // your data here
.Where(p => p.product.StartsWith(term))
.Take(10)
.Select(p => new
{
// jQuery UI needs the label property to function
label = p.product.Trim()
});
// Json returns [{"label":value}]
return Json(model, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Settings.ReportException(ex);
return Json("{'ex':'Exception'}");
}
}
JavaScript:
This code is when you select a value from the list that is displayed from your search. The 'window.location.href' redirects to a different controller once a value from the autocomplete has been selected.
// submits form upon selecting a value
var submitAutocompleteForm = function (event, ui) {
var $input = $(this); // the HTML element (Textbox)
// selected value
$input.val(ui.item.label); // ui.item.label = the label value (product)
window.location.href = "/Product/Details?id=" + ui.item.label;
};
The next function sets up the autocomplete API. You declare your options, the above is optional and it comes under select, the source is required and it points to the data-attribute on the HTML element.
var createAutocomplete = function () {
var $input = $(this); // the HTML element (Textbox)
var options = {
// selecting the source by finding elements with the 'data-' attribute
source: $input.attr("data-autocomplete"), // Required
select: submitAutocompleteForm // Optional
};
// apply options
$input.autocomplete(options);
};
// targets input elements with the 'data-' attributes and each time the input changes
// it calls the 'createAutocomplete' function
$("input[data-autocomplete]").each(createAutocomplete);
You'll have to reference the jQueryUI file for autocomplete to work.
I'm trying to set up a page where I display a list of items and the details of the selected item. I have it working but wonder whether I have followed the correct approach. I'll use customers as an example
I have set the aspx page to inherit from an IEnumerable of Customers. This seems to be the standard approach to display the list of items. For the Details I have added a Customer user control which inherits from customer.
I think i'm on the right track so far but I was a bit confused as to where I should store the id of the customer whose details I intend to display. I wanted to make the id optional in the controller action so that the page could be hit using "/customers" or "customers/1" so I made the arg optional and stored the id in the ViewData like this:
public ActionResult Customers(string id = "0")
{
Models.DBContext db = new Models.DBContext();
var cList = db.Customers.OrderByDescending(c => c.CustomerNumber);
if (id == "0")
{
ViewData["CustomerNumber"] = cList.First().CustomerNumber.ToString();
}
else
{
ViewData["CustomerNumber"] = id;
}
return View("Customers", cList);
}
I then rendered the User control using RenderPartial in the front end:
<%var CustomerList = from x in Model
where x.CustomerNumber == Convert.ToInt32(ViewData["CustomerNumber"])
select x;
Customer c = (Customer)CustomerList.First(); %>
<% Html.RenderPartial("Customer",c); %>
Then I just have an actionLink on each listed item:
<%: Html.ActionLink("Select", "Customers", new { id = item.CustomerNumber })%>
It all seems to work but as MVC is new to me I would just be interested in others thoughts on whether this is a good approach?
In regards to proper MVC and separations of concerns, you shouldn't be calling LINQ queries in your view. To get around that, change your controller action code from what you have to this:
if (id == "0")
{
ViewData["CustomerDetails"] = cList.First();
}
else
{
ViewData["CustomerDetails"] = From x in db.customers where x.id = cInt(id);
}
then your partial
<% Html.RenderPartial("Customer",ViewData["CustomerDetails"]); %>
Are you showing the customer information on the same screen that you have your list of customers and not a separate view?
In this case I would take the following approach.
Display a list of customer's, be it a listbox or drop down list.
Let's assume it's a drop down list, probably not very user friendly
You would have the text as the customer name and then the value as the customer id
<select title="Customers">
<option label="Pieter" value="001"></option>
</select>
and using JQuery's $.getJSON you could load the new data via a call to an asp.net MVC action.
Note that your Action should return JsonResult