Retrieve fields from database without emulating them? [closed] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I have a small test program in ASP.NET MVC4 which allows you to select items from a dropdown menu. It uses Json and JavaScript (I'm not familiar with these at all).
Here's the code I have at the moment:
HomeController:
public ActionResult CountryList()
{
IQueryable countries = Country.GetCountries();
if (HttpContext.Request.IsAjaxRequest())
{
return Json(new SelectList(
countries,
"CountryCode",
"CountryName"), JsonRequestBehavior.AllowGet
);
}
return View(countries);
}
public ActionResult StateList(string CountryCode)
{
IQueryable states = State.GetStates().Where(x => x.CountryCode == CountryCode);
if (HttpContext.Request.IsAjaxRequest())
return Json(new SelectList(
states,
"StateID",
"StateName"), JsonRequestBehavior.AllowGet
);
return View(states);
}
View:
#section scripts {
<script type="text/javascript">
$(function () {
$.getJSON("/Home/Countries/List", function (data) {
var items = "<option>---------------------</option>";
$.each(data, function (i, country) {
items += "<option value='" + country.Value + "'>" + country.Text + "</option>";
});
$("#Countries").html(items);
});
$("#Countries").change(function () {
$.getJSON("/Home/States/List/" + $("#Countries > option:selected").attr("value"), function (data) {
var items = "<option>---------------------</option>";
$.each(data, function (i, state) {
items += "<option value='" + state.Value + "'>" + state.Text + "</option>";
});
$("#States").html(items);
});
});
});
</script>
}
<h1>#ViewBag.Title</h1>
#using (Html.BeginForm())
{
<label for="Countries">Countries</label>
<select id="Countries" name="Countries"></select>
<br /><br />
<label for="States">States</label>
<select id="States" name="States"></select>
<br /><br />
<input type="submit" value="Submit" />
}
and finally the Models:
Country
public class Country
{
public string CountryCode { get; set; }
public string CountryName { get; set; }
public static IQueryable<Country> GetCountries()
{
return new List<Country>
{
new Country {
CountryCode = "CA",
CountryName = "Canada"
},
new Country{
CountryCode = "US",
CountryName = "United-States"
}
}.AsQueryable();
}
}
}
State:
public class State
{
public string CountryCode { get; set; }
public int StateID { get; set; }
public string StateName { get; set; }
public static IQueryable<State> GetStates()
{
return new List<State>
{
new State
{
CountryCode = "CA",
StateID=1,
StateName = "Ontario"
},
new State
{
CountryCode = "CA",
StateID=2,
StateName = "Quebec"
},
new State
{
CountryCode = "CA",
StateID=3,
StateName = "Nova Scotia"
// .. and so on
}.AsQueryable();
}
}
}
My question is: how do I make this solution work with a database table? What do I need to do in order to make this same dropdown work with fields from a database? Does anyone have any useful tutorials that they could recommend?

You need to choose how you will access your database. There are a lot of options, but I recommend you to use some kind of ORM. It's not easy to choose an ORM too. So you will need to do a research before and find one that fits your needs best. As you wrote in comment you are new to this, so I will provide few samples of how fetching of States might look in different ORM's.
Dapper - ORM used on this (SO) site.
using (var conn = new SqlConnection("CONN_STR"))
{
IList<State> states = conn
.Query<State>(
"select * States where CountryCode = #CountryCode",
new { CountryCode = countryCode })
.ToList();
}
As you can see here we just provide SQL and object with object with parameters and Dapper does all things for us. We get list of entities.
Entity Framework - ORM created by Microsoft.
IList<State> states =
DbContext.States.Where(state => state.CountryCode == countryCode).ToList();
You don't need to write any SQL at all, we are using pure LINQ syntax.
Of course all ORM's has their pros and cons, so again, you need to do a research before.
EDIT: It seems that you have problems with filling selects... Then first you will need to create correct models for EF. You can reuse your existing models, just add some attributes:
[Table("Countries")]
public class Country
{
public string CountryCode { get; set; }
public string CountryName { get; set; }
}
[Table("States")]
public class State
{
[Key]
public int StateID { get; set; }
public string StateName { get; set; }
public string CountryCode { get; set; }
}
In Table attribute you should use your real table names of course. Then you need to create DbContext:
public class MyDbContext : DbContext
{
public DbSet<Country> Countries { get; set; }
public DbSet<State> States { get; set; }
}
Don't forget to specify connection string in web.config like in tutorial.
I simplified methods for getting countries and states and now they return only JSON:
public ActionResult CountryList()
{
using (var db = new MyDbContext())
{
var countries = db.Countries.ToList();
return Json(
new SelectList(countries, "CountryCode", "CountryName"), JsonRequestBehavior.AllowGet);
}
}
public ActionResult StateList(string countryCode)
{
using (var db = new MyDbContext())
{
var states = !string.IsNullOrEmpty(countryCode)
? db.States.Where(state => state.CountryCode == countryCode).ToList()
: new List<State>();
return Json(
new SelectList(states, "StateID", "StateName"), JsonRequestBehavior.AllowGet);
}
}
It's a good idea to move DB access code to different class but I hope you can do it yourself.
You had some strange URl's in you javascript so here is working example:
$.getJSON("/Home/CountryList", function (data) {
// Same code that you have
});
$("#Countries").change(function () {
$.getJSON("/Home/StateList?countryCode=" + $("#Countries > option:selected").attr("value"), function (data) {
// Same code that you have
});
});

If you need to get the list of countries or states from a database then what you need to do is be able to query the database. See these examples of using ado.net to query a database. https://msdn.microsoft.com/en-us/library/vstudio/dw70f090%28v=vs.100%29.aspx
Then just change your .GetCountries and GetStates to get the list from the database. The code will look something like this (this is just pseudocode)
var List<States> l = new List<States>();
while(reader.read()){
var s = new State{
CountryCode = reader["cc_code"],
StateID=reader["stateId"],
StateName = reader["stateName"]
};
l.add(s);
}
return l;

Related

Referencing data from ASP.NET MVC controller in Javascript file

I am currently working on a project that implements ComponentOne studio's Wijmo frameworks and I have built a grid that uses data passed from a Model that basically builds some dummy data for an individual sale.
I am then calling the public static IEnumerable in my Controller file which is passing a value for the number of data entries to create. That is being passed to my view for my Index cshtml file, where the data grid is being built.
I am trying to then figure out how to call the data that has been created when I am writing a function in a JS file. I want to be able to take the collective data that was produced by the int value in my controller (say 100 entries) and then create a view of that data that I am filtering on. However, I can't figure out how to pass that initial data so that when I run the filter on it I can reference that data to save a view of the output and run a secondary filter.
I basically need to figure out how the reference in the JS calls not just the model, but the model with the int value from the controller.
Here is the model file:
using System;
using System.Collections.Generic;
using System.Linq;
namespace FilterPanel.Models
{
public class Sale
{
public int ID { get; set; }
public DateTime Start { get; set; }
public string Country { get; set; }
public string Product { get; set; }
public bool Active { get; set; }
private static List<string> COUNTRIES = new List<string> { "US", "UK", "Canada", "Japan", "China", "France", "German", "Italy", "Korea", "Australia" };
private static List<string> PRODUCTS = new List<string> { "Widget", "Gadget", "Doohickey" };
/// <summary>
/// Get the data.
/// </summary>
/// <param name="total"></param>
/// <returns></returns>
public static IEnumerable<Sale> GetData(int total)
{
var rand = new Random(0);
var dt = DateTime.Now;
var list = Enumerable.Range(0, total).Select(i =>
{
var country = COUNTRIES[rand.Next(0, COUNTRIES.Count - 1)];
var product = PRODUCTS[rand.Next(0, PRODUCTS.Count - 1)];
var startDate = new DateTime(dt.Year, i % 12 + 1, 25);
return new Sale
{
ID = i + 1,
Start = startDate,
Country = country,
Product = product,
Active = (i % 4 == 0)
};
});
return list;
}
}
}
I am then referencing this function in the controller file:
using FilterPanel.Models;
using System.Linq;
using System.Web.Mvc;
namespace FilterPanel.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View(Sale.GetData(100).ToList());
}
}
}
And finally trying to call that data in my JS file with "data" being a placeholder for the Sale.GetData(100) that I am trying to pass
var view = new wijmo.collections.CollectionView(data);
// create a second CollectionView based on the first one
var view2 = new wijmo.collections.CollectionView(view.items, {
collectionChanged: function(s) {
var cnt = document.getElementById('cnt');
cnt.textContent = wijmo.format('{length:n0}', s.items)
}
});

Getting Value from DropDownList to partial view using Ajax

I'm a novice in javascript, and a junior developper in OOP.
After many attempts and many google search I dind't make it to solve it.
I have a DropDownList and a Partial View. I want to give the selected value to the partial view controller. It works when I write the value directly in, but it doesn't if i try to catch the DropDownList value. For the moment the value returned is always empty.
Model
public partial class Clients
{
public int ClientID { get; set; }
public string Code { get; set; }
public string Nom { get; set; }
public string Adresse1 { get; set; }
public string Adresse2 { get; set; }
public string CP { get; set; }
public string Ville { get; set; }
public Nullable<System.DateTime> DateCreation { get; set; }
public Nullable<System.DateTime> DateModification { get; set; }
}
View
#Html.DropDownList("id", (IEnumerable<SelectListItem>)ViewData["oas"], new { #id = "ClientID" })
<div id="result"></div>
<script>
$(function () {
$('#ClientID').change(function () {
//var pid = $("#id").val();//$(this).data('id');
$('#result').load('#Url.Action("filter")',
{ id: $("#id").val() } //replacing $("#id").val() by "3" makes it work, but i of course don't a constant value here
);
});
});
Controller
public class OnePageController : Controller
{
Entities db = new Entities();
public ActionResult Index()
{
List<SelectListItem> list = new List<SelectListItem>();
list.Add(new SelectListItem { Text = "-Please select-", Value = "Selects items" });
var clts = (
from c in db.Clients
select c).ToArray();
for (int i = 0; i < clts.Length; i++)
{
list.Add(new SelectListItem
{
Text = clts[i].Nom,
Value = clts[i].ClientID.ToString(),
Selected = (clts[i].ClientID == 1)
});
}
ViewData["oas"] = list;
return View(/*db.Clients.ToList()*/);
}
[HttpPost]
public ActionResult Filter(string id)
{
var contact = from c in db.Contacts
where c.ClientID.ToString() == id
select c;
return PartialView(contact);
}
}
Any idea would be greatly appreciated, also i don't know how to debug javasript, i use the developper tools in my when browser to try to catch the values, but i don't really track the changes..
You should change a bit your script:
$(function () {
// You select the element with id = ClientID
var clientEle = $('#ClientID');
// You register an event handler for the change of the selected value
clientEle.change(function () {
// clientEle.val() would return the selected value
$('#result').load('#Url.Action("filter")',{ id: clientEle.val() });
});
});
Regarding how you should debug JavaScript I would suggest to write the following keyword a few lines before you want to start the debugging:
debugger;
Then open developer tools and refresh your page. When JavaScript engine hits the debugger would stop it's execution and from this moment you could examine you code line by line.
For a thorough understanding in how you could debug JavaScript, you could start by checking the following links
https://developers.google.com/web/tools/chrome-devtools/javascript/
https://developer.mozilla.org/en-US/docs/Mozilla/Debugging/Debugging_JavaScript
https://www.w3schools.com/js/js_debugging.asp

Knockout-jqAutoComplete displays the ID value instead of the name during editing

I'm using Knockout 2.2.1, JQuery 1.9.1, and Ryan Niemeyer's Knockout-jqAutoComplete 0.4.3.
The application allows the user to add a contact to a list of contacts. The contact information comes from a list of possible contacts.
We are using a span to display the names of contacts that exist in the database and data model on page load. When the user clicks the name, they have the opportunity to edit or delete the contact. We hide the span and show an input field in its place. This field is the AutoComplete field and it should show the Name of the contact.
The user can also click a button to add a new contact, which adds a new row with an input field which also uses AutoComplete.
Information edited or added by the user is persisted when a save button is clicked.
The Problem
When the user enters editing mode, the input displays the ID instead of the name.
Here's an image of the data displayed on page load, and here's what it looks like when you switch to editing mode. In the second picture, we'd like for it to display "Doe, John" instead of the primary key from the database.
Using an older version of Knockout-jqAutoComplete, this was not an issue. (We updated to the current version because there were other problems.) I can't find a version number on it, but it was used by including a Razor partial, "_jqueryAutoCompleteBinding.cshtml". The binding for this old version was:
//Deprecated, no longer in use.
<input data-bind="jqAuto: { autoFocus: false }, jqAutoSource: optionsProfessionalsAuto, jqAutoQuery: getProfessionals, jqAutoValue: ProfessionalId, jqAutoSourceLabel: 'displayName', jqAutoSourceInputValue: 'Name', jqAutoSourceValue: 'Id'" class="edit-data Name" />
The binding we're now using is:
<input data-bind="jqAuto: { source: getProfessionals, value: ProfessionalId, valueProp: 'ProfessionalId', labelProp: 'Name', inputProp: 'Name', options: { autoFocus: false } }"class="edit-data Name" />
And here is the relevant portion of the AppViewModel:
function AppViewModel() {
//{...}
self.addProfessionalContact = function () {
var skip = this.ProfessionalContacts().length * 14 - 1; // rows * columns - 1
this.ProfessionalContacts.push({
Name: ko.observable(''),
Specialty: ko.observable(''),
City: ko.observable(''),
State: ko.observable(''),
ProfessionalId: ko.observable(),
optionsProfessionalsAuto: ko.observableArray() //deprecated?
});
WireUpEditGridEvents();
SetDisabled();
RegisterDatePicker();
WireUpPostAddEvents(skip, 'professionalContacts');
$("#professionalContacts tr").last().find(".display-data").hide();
//{...}
}
(Edit 1)
Here is GetProfessionals, as requested:
function getProfessionals(searchTerm, sourceArray) {
try {
$.ajax({
type: "GET"
, contentType: 'application/json; charset=utf-8'
, url: '#Url.Action(MVC.Professional.ActionNames.GetProfessionals, MVC.Professional.Name)?searchTerm=' + searchTerm
, dataType: "json"
, success: function (data) {
var result = [];
for (var i = 0; i < data.length; i++) {
var specialty = data[i].Specialty ? data[i].Specialty + " - " : "";
result.push({ Name: data[i].Name + " (" + specialty + data[i].City + ", " + data[i].State + ")", ProfessionalId: data[i].ProfessionalId });
}
sourceArray(result);
}
}
)
.fail(function () { $.unblockUI(); $.growlUI('Error', 'Failed to get professionals. Unknown error.'); });
} catch (e) {
$.unblockUI();
throw e;
}
(Edit 2)
I think I do need some further clarification.
The getProfessionals function returns a list of type ProfessionalContactEditViewModel. This class contains several properties:
public class ProfessionalContactEditViewModel
{
public int? ClientContactId { get; set; }
public int ProfessionalId { get; set; }
public string Name { get; set; }
public string Specialty { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public bool Send { get; set; }
public bool ReferredBy { get; set; }
public bool Delete { get; set; }
//Added based on RPNiemeyer's response
//public NameIdViewModel ProfessionalNameId
//{
// get
// {
// return new NameIdViewModel()
// {
// Name = this.Name,
// Id = this.ProfessionalId,
// };
// }
// set
// {
// this.Name = value.Name;
// this.ProfessionalId = value.Id ?? default(int);
// }
//}
}
Based upon RP's answer, I added a NameIdViewModel obj. which returns the Name and ProfessionalId. This, however, is not turned into an observable as a nested object, so we're now passing the entire ProfessionalContactViewModel from getProfessionals:
result.push(ko.toJSON(data));
I have removed valueProp from the input binding; it otherwise reads the same as before, but I'm still seeing a number when I edit a contact.
The browser tab also freezes for a few seconds when searching for a contact by name, and displays a completely blank list. The former of these two new issues may be due to the larger amount of data.

MVC 4 Razor - Creating a dynamic DropDownList

I'm trying to create a view which has two DropDownLists. The options available in the second DropDownList depend upon what the user has selected in the first. I'm passing this data to my view in the ViewBag as follows:
List<SelectListItem> firstBoxChoices = ViewBag.firstBoxChoices;
Dictionary<string, List<SelectListItem>> secondBoxDict = ViewBag.secondBoxDict;
The first object has the choices for the first DropDownList. When the user selects one of those, I need to get the appropriate list of choices for the second DropDownList from my Dictionary. I just can't figure out how to achieve this. If I get the new selection of the first DropDownList in a Javascript onchange() function, there doesn't seem to be any way to use this value as the key for my C# dictionary.
Of course, I've seen this functionality on the web so I know it must be possible somehow. How can I achieve this?
Thanks!
There are a couple ways of doing this without forcing you to store all the possible data items in the model, my preference is to use Javascript/JQuery. Here is an example of a Country/State cascading drop down:
Javascript used to get states when a country is selected:
<script type="text/javascript">
function AppendUrlParamTokens(url, params) {
for (var param in params) {
if (params[param] == null) {
delete params[param];
}
}
return url + "?" + jQuery.param(params);
}
function OnCountriesChange(ddl) {
jQuery.getJSON(AppendUrlParamTokens('#Url.Action("GetStates", "Data")', { countryId: ddl.options[ddl.selectedIndex].value }), function (result) {
var target = jQuery('#states_ddl');
target.empty();
jQuery(result).each(function() {
jQuery(document.createElement('option'))
.attr('value', this.Value)
.text(this.Text)
.appendTo(target);
});
});
};
</script>
Country dropdown:
#Html.DropDownListFor(model => model.Country, new SelectList(Model.Countries, "Value", "Text", Model.PreviousCountrySelected), "(Select One)", new { id = "countries_ddl", onchange = "OnCountriesChange(this)" })
State dropdown:
Html.DropDownListFor(model => model.State,
Model.States != null
? new SelectList(Model.States, "Value", "Text", Model.PreviousStateSelected)
: new SelectList(new List<SelectListItem>(), "Value", "Text"),
new { id = "states_ddl" })
Controller method to retrieve states:
public ActionResult GetStates(short? countryId)
{
if (!countryId.HasValue)
{
return Json(new List<object>(), JsonRequestBehavior.AllowGet);
}
var data = GetAllStatesForCountry(countryId.Value).Select(o => new { Text = o.StateName, Value = o.StateId });
return Json(data, JsonRequestBehavior.AllowGet);
}
The idea is that on selection of dropdown 1 you use ajax to go retrieve your second dropdown's value.
Edit: Forgot to include utility method for constructing urls
The .change event of your first select should populate the second select by calling a server method that returns the option data based on the selected value. Given the following view model
public class MyModel
{
[Required(ErrorMessage = "Please select an organisation")]
[Display(Name = "Organisation")]
public int? SelectedOrganisation { get; set; }
[Required(ErrorMessage = "Please select an employee")]
[Display(Name = "Employee")]
public int? SelectedEmployee { get; set; }
public SelectList OrganisationList { get; set; }
public SelectList EmployeeList { get; set; }
}
Controller
public ActionResult Edit(int ID)
{
MyModel model = new MyModel();
model.SelectedOrganisation = someValue; // set if appropriate
model.SelectedEmployee = someValue; // set if appropriate
ConfigureEditModel(model); // populate select lists
return View(model);
}
[HttpPost]
public ActionResult Edit(MyModel model)
{
if(!ModelState.IsValid)
{
ConfigureEditModel(model); // reassign select lists
return View(model);
}
// save and redirect
}
private void ConfigureEditModel(MyModel model)
{
// populate select lists
model.OrganisationList = new SelectList(db.Organisations, "ID", "Name");
if(model.SelectedOrganisation.HasValue)
{
var employees = db.Employees.Where(e => e.Organisation == model.SelectedOrganisation.Value);
model.EmployeeList = new SelectList(employees, "ID",
}
else
{
model.EmployeeList = new SelectList(Enumerable.Empty<SelectListItem>());
}
}
[HttpGet]
public JsonResult FetchEmployees(int ID)
{
var employees = db.Employees.Where(e => e.Organisation == ID).Select(e => new
{
ID = e.ID,
Name = e.Name
});
return Json(employees, JsonRequestBehavior.AllowGet);
}
View
#model MyModel
....
#Html.LabelFor(m => m.SelectedOrganisation)
#Html.DropDownListFor(m => m.SelectedOrganisation, Model.OrganisationList, "-Please select-")
#Html.ValidationMessageFor(m => m.SelectedOrganisation)
#Html.LabelFor(m => m.SelectedEmployee)
#Html.DropDownListFor(m => m.SelectedEmployee, Model.EmployeeList, "-Please select-")
#Html.ValidationMessageFor(m => m.SelectedEmployee)
....
Script
var url = '#Url.Action("FetchEmployees")';
var employees = $('SelectedEmployee');
$('#SelectedOrganisation').change(function() {
employees.empty();
if(!$(this).val()) {
return;
}
employees.append($('<option></option>').val('').text('-Please select-'));
$.getJson(url, { ID: $(this).val() }, function(data) {
$.each(data, function(index, item) {
employees.append($('<option></option>').val(item.ID).text(item.Text));
});
});
});

Knockout failing to post a form, can't figure out why

I am developing a page with ASP.NET MVC and API, using Knockout, Typescript, and the code is as: JSFiddler
The server code:
// POST: api/Empresas
[ResponseType(typeof(Business))]
public async Task<IHttpActionResult> PostBusiness(Business business)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Businesses.Add(business);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = business.Id }, business);
}
Business Obj:
public class Business
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[ScaffoldColumn(false)]
public Guid Id { get; set; }
[Display(Name = "CNPJ", Description = "Cadastro Nacional de Pessoa Juridica")]
public string CNPJ { get; set; }
[Display(Name = "Nome", Description = "Razão Social")]
public string Name { get; set; }
[Display(Name = "Limite Mensal", Description = "Limite mensal de uso")]
public int MonthlyLimit { get; set; }
[Display(Name = "Mensal Atual", Description = "Uso Mensal Atual")]
public int MonthlyCurrent { get; set; }
[Display(Name = "Inicio Assinatura", Description = "Data inicial da assinatura")]
public DateTime SubscriptionStart { get; set; }
[Display(Name = "Meses Contratados", Description = "Numero de meses contratados")]
public int MonthContractCount { get; set; }
}
The example is not gonna work since there is not an end point to test against.
My first question is why won't the data-bind work for this?
Second and most important, I keep getting the following error message:
Message from webpage
[object Object]
parsererror
SyntaxError: Invalid character - failed to create business
OK
I have no idea why this is happening, and I have done multiple changes to the code with success. Any ideas?
Values I was using:
CNPJ = 123.321.321-25
Name = Test Business
monthlyLimit = 20000
SubscriptionStart = 01/01/2014
monthContractCount = 24
Thanks in advance
EDIT:
createBusiness = (formElement) => {}
I changed the signature on the method to look like the above, with attempt to solve the scope problem with "this" key word. Still not working though.
NEW EDIT:
createBusiness = (formElement) => {
$(formElement).validate();
if ($(formElement).valid()) {
var formserialized = $(formElement).serialize();
$.post('/Api/Empresas/', formserialized, null, "json")
.done((result) => {
this.Business.Id = result.Id;
this.Business.Name(result.Name);
this.Business.CNPJ(result.CNPJ);
this.Business.MonthlyLimit(result.MonthlyLimit);
this.Business.SubscriptionStart(result.SubscriptionStart);
this.Business.MonthContractCount(result.MonthContractCount);
this.Business.MonthlyCurrent(result.MonthlyCurrent);
})
.fail((x, y, z) => {
alert(x + '\n' + y + '\n' + z + ' - failed to create business');
});
};
}
This is the last change, and it worked now, but as you can see I had to change the this.BaseUri to '/Api/Empresas/' this change was necessary due to scope of "this", so this is a fix but not really. Any ideas there?
change
var formserialized = $(formElement).serialize();
to
var formserialized = JSON.stringify($(formElement).serialize());

Categories