Ajax jquery autocomplete in ASP.NET MVC 5 C# - c#

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.

Related

ASP.net MVC/EF/C# add none related table records to query in controller

I am trying to add records from table position for positionName(s) to let user select a position for employee when editing.My last attempts is to add a navigation property like field in company model
public virtual ICollection<Position> Mpositions { get; set; }
But all I got so far is null ref exception or no element in viewModel with property "PositionName" ass per viewbag didn't bother using everybody keeps recommending to avoid it so not going to do so either.
public ActionResult Edit([Bind(Include = "CompanyID,CompanyName,EntityForm,Address,Dissolute,CreationDate,FiscaleYear,Description")] Company company)
{
var GlbUpdate = db.Companies.Include(c => c.Members).Include(p => p.Mpositions);
List<Company> mdlCompanies = new List<Company>();
foreach (var item in GlbUpdate)
{
if ((item.Mpositions==null) || (item.Mpositions.Count() == 0))
{
item.Mpositions = (ICollection<Position>)new SelectList(db.Positions.Except((IQueryable<Position>)db.Positions.Select(xk => xk.Members)), "PositionID", "PositionName");
}
mdlCompanies.Add(item);
//I tried first to edit the Mpositions property directly in gblUpdate
//item.Mpositions = (IEnumerable<Position>)db.Positions.Select(p => new SelectListItem { Value = p.PositionID.ToString(), Text = p.PositionName}) ;
//(ICollection<Position>)db.Positions.ToListAsync();
}
In the view I have this
List<SelectListItem> mPositionNames = new List<SelectListItem>();
#*#this yields no results if I try gettign it from the compani record itself it gives a logic error where all id match all positionNames impossible to select an item and only positions already registered are available on the dropDownlist*#
#{foreach (var item in Model.Mpositions)
{
mPositionNames.Add(new SelectListItem() { Text = item.PositionName, Value = item.PositionID.ToString(), Selected = (false) ? true : false });
#*#selected attribute set to false not an issue, no data to select from :p so far*#
}
}
#*#null exception(if i try to midify Mpositions directly in controler) here or empty list if modify it then put it with original query in a new list*#
<div class="SectionContainer R-sectionContainerData" id="MwrapperDataRight">
#Html.DropDownListFor(mpos => item.PositionID, (SelectList)Model.Mpositions)
</div>
All I want to do is pull the positions table to create a drop downList so users can change the position of an employee but since position has a 1>many relation with employee not companies it is not bound automatically by EF nor I seem to be able to use Include() to add it.
Your query for editing positions are complex. This query must edit person's info only. Using Edit action for formalizing position's edit are not correct.It's againts to Single Responsibility Principle. Use ViewComponents for this situation. Load positions separately from person info.
I found a suitable solution using a model that encapsulate the other entities then using Partialviews/RenderAction so each part handles one entity/operation.

Dynamic default selected value for MVC DropDownList

I feel that the answer for this has to be out there in several places as variations of this question seem to get asked a lot. Unfortunately I cannot grasp exactly how to do what I am trying to achieve, so your help is greatly appreciated once again.
I have a list of usergroups, which are each assigned to a staff member. This is done by iterating through the list of usergroups and showing a dropdown of available staff members beside each one. It should be possible to not assign a staff member also, so a null value select option should be available.
When a new group is being created, having the null value as the default is fine, but where I am just updating an existing record, I want the dropdown to default to the option with the matching staff member ID.
So I query for available staff members:
var rtrnStaff = (from st in db.PrmTbl_Staffs
join sal in db.PrmTbl_Salutations on st.SalutationID equals sal.ID
where st.Active == true
select new { st.ID, Name = sal.Desc + ". " + st.Name });
To insert a blank value into this array:
List<SelectListItem> staff = new SelectList(rtrnStaff, "ID", "Name").ToList();
staff.Insert(0, (new SelectListItem { Text = "None", Value = "0" })); //can value be = null?
In my view, for the form to create a new user group, I can provide a dropdown like so:
#Html.DropDownList( "staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"])
This provides a dropdown, with the "None" option first, which is fine. However, when I try the same thing for my update form, with the addition of a default value argument, it doesn't work:
#Html.DropDownList( "staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], item.StaffID)
The intention being that when placed within a foreach loop, the option matching the relevant staffID would show as default. Instead, "none" is still the first option.
I did try to just query the table in my controller, not build a selectlist there but pass the results directly via ViewData to the View, and then in the View do the following:
#Html.DropDownList("staffID", new SelectList(
(System.Collections.IEnumerable) ViewData["Staff"], "ID", "Name", item.StaffID),
new { Name = "staffID" })
That works no probs, but without a "none" option. Clearly I need some middle ground! Between DropDownList, DropDownListFor, List, SelectList, etc., I'm confused.
EDIT
(To show current state of code)
Controller:
var rtrnStaff = (from st in db.PrmTbl_Staffs
join sal in db.PrmTbl_Salutations on st.SalutationID equals sal.ID
where st.Active == true
select new { st.ID, Name = sal.Desc + ". " + st.Name });
List<SelectListItem> staff = new SelectList(rtrnStaff, "ID", "Name").ToList();
ViewData["StaffwNull"] = staff;
View:
//show dropdown of all staff,
//defaulting to "None" value (works)
#Html.DropDownList("staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], "None")
//show dropdown of all staff,
//defaulting to value matching item.staffID (doesn't work)
//default selection is first list item
//and list doesnt include "None" option
#foreach (var item in Model)
{
...
var thisStaffID = item.StaffID;
....
#Html.DropDownList( "staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], thisStaffID)
}
There is no overload where you can specify a selected value. MVC searches in the ViewBag object for an item called staffID and use that as selected value. You can use this overload of the DropDownList method which allows you to specify an option label:
#Html.DropDownList("staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], "None")
This renders an extra option to the select list at the top so you don't have to do this manually.
Side note: you should look into MVC model binding.
You can give an ID to the dropdown list (this overload) and then use jQuery to update it.
View
#Html.DropDownList("staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], new { id = "dropdown1" })
jQuery
<script>
$(document).ready(function () {
$('#dropdown1').val('theValueYouWantSelected');
});
</script>

How to use grid in VS2010 MVC3 to add and edit data?

I'm using Microsoft VS 2010 C#, MVC3.
I have Calsserooms and Students with many to many relation ship, so I add an intermediat table called Classroom_Students.
When adding students to a classroom, I use a combo box in my view filled with all students names, I choose one by one in every submit
#using (Html.BeginForm("AddStudentToClassroom", "Calssrooms", FormMethod.Post))
{
#Html.LabelFor(c=>c.Students, "Choose a Student")
<select name = "StudentID">
#foreach (var it in Model.Students)
{
<option value="#it.ID">#it.StudentName </option>
}
</select>
<input type="submit" value= "Add" />
}
My question is:
How can I use gride, instead of this combo, to select many students, select all or deselect all to add???
I'll appreciate any help.
This is the code in my controller.
For page first call, I fill combobox as following:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult AddStudentToClassroom(int id) //id of calssroom
{
using (ExaminationEntities en = new ExaminationEntities())
{
ClassroomDetails ClsromView = new ClassroomDetails (); // these are for
ClsromView.Classroom = en.Classroom.Single(c => c.ID == id);// loading calssroom information and to
ClsromView.Students = en.Students.ToList(); // fill students list for the combobox
return View(ClsromView);
}
}
When submiting the form, view, and click the add button, it calls the following overloaded add function for saving data:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddStudentToClassroom(AddStudToCals ClasStud) //ClasStud is the submited data from the view
{
using (ExaminationEntities en = new ExaminationEntities())
{
ClassroomDetails ClsromView = new ClassroomDetails(); // these are for
ClsromView.Calssroom = en.Calssroom.Single(c => c.ID == ClasStud.ClassroomID); // loading calssroom information and to
ClsromView.Students = en.Student.ToList(); // fill students list for the combobox
using (ExaminationEntities exn = new ExaminationEntities())
{
Calssroom_Student To_DB_ClasStud = new Calssroom_Student (); //To_DB_ClasStud object to get the submited values and to save it in the DB
To_DB_ClasStud.CalssroomID = ClasStud.CalssroomID;
To_DB_ClasStud.StudentID = ClasStud.StdentID;
en.AddToClassroom_Student(To_DB_ClasStud);
en.SaveChanges();
}
return View(ClsromView);
}
}
Well, the option that requires the least changes to your markup is to add the multiple property to your select. Then, change the action method to accept a params int[] ids, iterate through them, and you should be good-to-go. At worst, you might have to change your parameter to a string and do a Split() on ,, but I don't recall that being how the model binder supports multi-selects.
If this doesn't seem to fit your needs, there is an article on the ASP.NET website that explains using a MultiSelectList to bind to the ListBox helper, here:
http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and-jquery/using-the-dropdownlist-helper-with-aspnet-mvc

How to fill document header from jqgrid data

ASP .NET MVC2 page contains order header data (order number, customer, order data etc):
<form id='_form' class='form-fields' action='' onsubmit='SaveDocument();return false;'>
<input id='Number' name='Number' />
<select id='PaymentTerm' name='PaymentTerm'>
<option value=''></option><option value='0'>Cash</option>
<option value='10'>10 days</option>
</select>
</form>
and order rows presented in jqgrid.
I'm looking for a way to fill order headcer data from json date from controller like
like jqgrid fills data.
To minimize request maybe it is best to return header data in jqgrid data request.
For this additional parameter documentId is passed to controller.
GetData returns document header as name value pairs in document object.
How to assign those values to form elements in browser in jqgrid loadcomplete or other place ?
public JsonResult GetData(int page, int rows, string filters,
int documentId )
{
var query = ...;
var totalRecords = query.Count();
var documentHeader = new FormCollection();
// In production code those values are read from database:
documentHeader.Add("Number", 123); // form contains input type='text' name='Number' element
documentHeader.Add("PaymentTerm", "10"); // form contains select name='PaymentTerm' element
...
return Json(new {
total = page+1,
page=page,
document = documentHeader,
rows = (from item in query
select {
id = item.Id.ToString(),
cell = new[] {
item.ProductCode,
item.ProductName,
item.Quantity,
item.Price
}
}).ToList()
},
JsonRequestBehavior.AllowGet);
}
If I understand correct your question you can use beforeProcessing or loadComplete callbacks to fill the form data based on the response from the server. The first data parameter of both callbacks (beforeProcessing or loadComplete) will contains all the data returned from the server. So you have access to document property of data and it has the same format as on the server.
I am not sure why you use document of the type FormCollection. It seems to me the most native to use anonymous type of data:
return Json(new {
total = page + 1,
page = page,
document = new {
number = 123,
paymentTerm = 10
},
rows = (...)
},
JsonRequestBehavior.AllowGet);
but the exact type of document is probably not so important.
Inside of beforeProcessing or loadComplete you can just use the corresponding properties of data.document in the same format. For example
beforeProcessing: function (data) {
var hearderData = data.document;
if (hearderData) {
if (hearderData.number) {
$("#Number").val(hearderData.number);
}
if (hearderData.paymentTerm) {
$("#PaymentTerm").val(hearderData.paymentTerm);
}
}
}

MVC 2: How can I create links from Dropdown list options available when list datasource is a database

So I have multiple lists such as this one:
<%: Html.DropDownList("CPUList", new SelectList((IEnumerable)ViewData["CPUList"], "Price", "Name"))%>
The datasource is a LinQ to SQL *.dbml model
Controller assigns data to the ViewData as such, filtering results on string value "platform":
if (platform == "i7)
{
var processor = from prod in _ctx.Products
where prod.Attributes == 1366"
select prod;
var ram = from prod in _ctx.Products
where prod.Attributes == "TripleChannel"
select prod;
ViewData["CPUList"] = processor;
ViewData["RAMList"] = ram;
}
Basically I am attempting a PC customization page and I ideally would
like people to be able to click on their selected option like a link
to open a new small window with a detailed description of the component selected.
I already have a view that takes a productID as a parameter and basically
displays a long description (prod.LongDesc) for anyone particualr product.
Except I don't know how I go about creating the dropdown list of
links foreach available option/name and create the correct url that will open in a new window.
It's my first week of programming basically, so if you believe I am going a totally wrong way about implementing this function do let me know, seems to work great so far though populating the list as required according to parameters.
In your DropDownList I would rather use the product id as the value, this way you could just do an ajax request on that product id to get more information about it.
So you could have an Action that looks somewhat like the following:
public ActionResult GetRam(Guid productId)
{
var cpu = Products.First(x => x.Id == productId);
switch (cpu.Attribute)
{
case "1366":
ViewData["Ram"] = Products.Where(x => x.Attribute == "TrippleChannel").ToArray();
break;
case "1155":
ViewData["Ram"] = Products.Where(x => x.Attribute == "DualChannel").ToArray();
break;
}
return PartialView("_RamList");
}
However you might want to consider having a relationship between what parts are compatible with each other. But for now, consider the above action to make it easy.
If you have the product id as value in your dropdown you could simply do something like this using jQuery:
<script>
$(document).ready(function () {
$("#CPUList").change(function () {
$.ajax({
url: '/Product/GetRam/' + $(this).val(),
dataType: 'html',
success: function (data) {
$('#RAMListPlaceHolder').html(data);
});
});
});
</script>
Where RAMListPlaceHolder is a div where you will put the html from the partial view _RamList

Categories