In my ASP.NET Core app I have a cshtml page where I am trying to use the Twitter Typeahead.
Here is my markup:
<div id="type-ahead">
<input class="twitter-typeahead form-control" id="typeLocation" type="text" />
</div>
Here is my Javascript for the html input:
var substringMatcher = function (strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function (i, str) {
if (substrRegex.test(str)) {
matches.push(str);
}
});
cb(matches);
};
};
var locations = $.get('/Home/getlocationlist', function (data) {
});
$('#type-ahead .twitter-typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'locations',
source: substringMatcher(locations)
});
My question is pertaining to getting the data source for the typeahead. Here is my jQuery get:
var locations = $.get('/Home/getlocationlist', function (data) {});
This is my controller function that the $.get retrieves:
public ActionResult GetLocationList()
{
var list = ExecuteRows("SELECT LocationName FROM Location ORDER BY LocationName");
var locations = list.SelectMany(x => x.Values);
return Ok(locations);
}
The $.get function return data and assigns it to location var. The problem is that the data comes back as an array looking like this
{["Location 1","Location 2","Location 3"]}
However, as I start typing, the typeahead starts to display multiple lines where each line shows the array noted above.
I am trying to figure out how to properly process the data from the controller method into the typeahead.
Thank you!
as I start typing, the typeahead starts to display multiple lines where each line shows the array noted above.
To fix above issue, please try to modify the code to put the code of initializing a typeahead inside Ajax success callback function, like below.
var substringMatcher = function (strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function (i, str) {
if (substrRegex.test(str)) {
matches.push(str);
}
});
cb(matches);
};
};
$.get('/Home/getlocationlist', function (data) {
var locations = data;
$('#type-ahead .twitter-typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'locations',
source: substringMatcher(locations)
});
});
Test Result
Related
I'm trying to code a simple autocomplete using LINQ to entities and Razor (new to c# sharp as well) and i'm having trouble displaying json data in my view.
My controller is as follows:
public ActionResult AutoCompleteCity(string guess)
{
List<City> listData = null;
if (!string.IsNullOrEmpty(guess))
{
listData = db.AutoCompleteCity(guess);
}
return Json(new { Data = listData });
}
AJAX call:
function getCities(input) {
var serviceURL = $("#autocompleteURL").val();
var url =
$.ajax({
type: "POST",
url: serviceURL,
data: {
'guess': input
},
dataType: 'json',
success: function (response) {
if (response.Data != null) {
if ($("#targetUL") != undefined) {
$("#targetUL").remove();
}
Data = response.Data;
$.each(Data, function (i, value) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + JSON.stringify(value) + "</li>"));
});
});
}
I might be missing a bracket or two :D
Any way when i retrieve records from the database and try to pass JSON values to the view the output is:
{"Data":[{"Selected":false,"Text":null,"Value":null}]}
I assume I'm not passing the JSON listData correctly. Any input will be greatly appreciated, thanks!
EDIT: here is a screencap of the values returned by listData in my controller
This is my LINQ query
public List<City> AutoCompleteCity(string guess)
{
using (var context = new Sports.SportsEntities())
{
var query = (from loc in context.city
join prov in context.state on loc.STATE_ID equals prov.STATE_ID
where loc.CITY_DESC.Contains(guess.ToUpper())
select new
{
city = loc.CITY_DESC,
state = prov.STATE_DESC,
});
IEnumerable<City> cityList= from ba in query.AsEnumerable()
select new City(ba.city, ba.state);
return cityList.ToList();
}
}
This error:
{"Data":[{"Selected":false,"Text":null,"Value":null}]}
was caused by having declared private attributes in the City Class, or by failing to declare getter/setter methods if said attributes are meant to be private.
I figured that out by looking at the screen capture posted on my question, only displaying the "selected", "text" and "value" properties and not the city and state description in the query results, which was what I needed to display below the textbox input.
This controller method will do the trick:
public JsonResult AutoCompleteCity(string term)
{
List<City> listData = new List<City>();
if (!string.IsNullOrEmpty(term))
{
listData = db.AutoCompleteCity(term);
}
return Json(listData, JsonRequestBehavior.AllowGet);
}
The problem is probably this piece of code in the AJAX call:
if ($("#targetUL") != undefined) {
$("#targetUL").remove();
}
By doing this you are removing the ul tag from the DOM and therefore cannot add the li elements you are constructing in this piece of code:
$.each(Data, function (i, value) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + JSON.stringify(value) + "</li>"));
});
If you want to clear the list use .empty():
if ($("#targetUL") != undefined) {
$("#targetUL").empty();
}
if you want to return a JSON, change that:
public ActionResult AutoCompleteCity(string guess)
by
public JsonResult AutoCompleteCity(string guess)
and also try that:
Data = JSON.parse(response.Data);
It looks like your method returns a list of City objects, so maybe you need to use the property of that objects to get to the city name, something like this:
$.each(Data, function (i, city) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + city.Name + "</li>"));
});
I have a drop down list that I need to fill with datetime values passed from an ajax call. The values that populate look like this: "/date1234847269/" and not actual dates. I just need the dates to be passed into the drop down list. I do not need the time stamps that are also in the datetime value that is returned from the controller.
I'm not sure if jQuery has issues with handling c# datetime values and not strings. Any help would be appreciated. Thanks
My View:
<select id="ddlDate" class="form-control bold">
<option value='0'>--Select Date--</option>
</select>
My Ajax Call:
function loadDateDDL(historicalIsChecked, monthlyIsChecked) {
$.ajax({
type: 'POST',
url: '#Url.Action("GetGroupReportDates")',
dataType: 'json',
data: { isMonthly: monthlyIsChecked },
success: function (returnData) {
convertDate(returnData);
$("#ddlDate").empty();
$("#ddlDate").append("<option value='0'>--Select Date--</option>");
$.each(returnData, function (value, key) {
$("#ddlDate").append($("<option></option>")
.attr("value", value).text(key));
});
//alert(returnData);
},
error: function (ex) {
alert('Failed to retrieve dates.' + ex);
}
});
}
function convertDate(returnData)
{
var date = new Date(returnData);
return date;
}
My Controller:
public JsonResult GetGroupReportDates ( Boolean isMonthly )
{
List<DateTime> reportDates = RealmsModel.RealmsAuditDataInterface ( ).GetGroupQueryRptDates ( isMonthly );
return new JsonResult ( )
{
Data = reportDates,
MaxJsonLength = Int32.MaxValue
};
}
Update 1/21/2016:
I am now passing my json data "returnData" to the javascript function below and converting it based on another stack post: How do I format a Microsoft JSON date?
function convertDate(returnData)
{
var date = new Date(returnData);
return date;
}
This now gives me the error "date = Invalid Date {}, returnData = ["/Date(1451628000000)/"]". I feel like I'm getting close. Any help is appreciated.
I resolved this with the following:
function convertDate(returnData)
{
var pattern = /Date\(([^)]+)\)/;
var results = pattern.exec(returnData);
var dt = new Date(parseFloat(results[1]));
return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
}
The format you're seeing is the old "microsoft" way of formatting dates. There are 2 ways to get around it.
One way would be to use the JSON.Net serialiser instead of the built in JavaScriptSerializer, as it (since version 4.5) formats dates so that they can be automatically parsed.
Another (quicker) way would simply be to extract the numbers from the date in it's current format as pass them to a new javascript Date object.
function toDate(value) {
return new Date(parseInt(/Date\(([^)]+)\)/.exec(value)[1], 10));
}
I have some strings and I would like to get the Index Number out from them.
Here is the example.
var x = "FundList[10].Amount";
var y = "FundList[11].Amount";
var z = "FundList[15].Amount";
I simply want to get the 10,11,15 and put them into an array of Int.
Currently, I am using a stupid way, which is to replace "FundList[", "]" and ".Amout" with "".
I am wondering if there is a better way to do so.
Update
Here are some clarifications. Here is my code.
This is my part of my PartialView.
#{
var txtIndexName = "FundList[" + Model.Index + "].Index";
var txtAmountName = "FundList[" + Model.Index + "].Amount";
var dropFiscalYearName = "FundList[" + Model.Index + "].FiscalYear";
}
Amount: <input type="text" name="#txtAmountName" id="#txtAmountName" />
Here is the JavaScript to call the PartialView. Each time when user click on a anchor link, the PartialView will be called.
function LoadContractOptionFundingPlanBlockByIndexNumber(indexNumber) {
$.ajax({
type: "POST",
url: "/Json/LoadContractOptionFundingPlanPartialView",
data: JSON.stringify({ index: indexNumber }),
contentType: "application/json; charset=utf-8"
}).success(function (result) {
$("#ContractOptionFundingPlanBlock").append(result);
});
}
function GenerateOptionFundingPlanBlock() {
$("#lnkAddFundingBlock").click(function () {
LoadContractOptionFundingPlanBlockByIndexNumber(currentIndexNumber);
currentIndexNumber++;
});
}
$(document).ready(function () {
GenerateOptionFundingPlanBlock();
});
var currentIndexNumber = 10;
Here is my View:
<form action="#" method="post" name="formCreateContracOption" id="formCreateContracOption">
#Html.AntiForgeryToken()
#Html.LabelForRequired(x=>x.ThisContractOption.OptionName)
#Html.ValidationMessageFor(x=>x.ThisContractOption.OptionName)
#Html.TextBoxFor(x=>x.ThisContractOption.OptionName) <br/><br/>
Period of Performance
#Html.TextBoxFor(x=>x.ThisContractOption.OptionStartDate)
#Html.TextBoxFor(x=>x.ThisContractOption.OptionEndDate) <br /><br />
<a id="lnkAddFundingBlock" href="#">Add Funding Plan</a> <br/><br/>
<div id="ContractOptionFundingPlanBlock"></div>
<input type="submit" id="btnCreateContractOption" name="btnCreateContractOption" value="Submit" />
</form>
After all, when user clicks on the Submit button, the whole thing will be posted to the controller.
Here is my Controller.
[HttpPost]
public ActionResult CreateContractOption(int contractId, ContractOptionCreateEditViewModel viewModel, FormCollection form)
{
var fundList = new List<OptionFundingPlanObject>();
var allOptionAmountKeyList = form.AllKeys.Where(x => x.Contains("FundList") && x.Contains("Index")).ToList();
var indexNumberList = new List<int>();
foreach(var thisKey in allOptionAmountKeyList)
{
var convertedIndex = Convert.ToInt32(Regex.Match(thisKey, #"\d+").Value);
indexNumberList.Add(convertedIndex);
}
return View();
}
The reason I am asking is because it is not simply a How to Post a List to the controller question.
When the List starts with a ZERO index, and every other index is in a sequence, it is pretty easy to handle.
In my case, user may generate a new Option, by calling my Partial View. User will have the ability to remove the generated option, and create a new one. The index then changed. In this case, I have to find another way to solve the problem.
var x = "FundList[10].Amount";
int xIndex = Convert.ToInt32(Regex.Match(x,#"\d+").Value); //10
This is a werid question though. What are you doing? :)
If you are always going to have the strings in the form you provided you can split it on the brackets and get the item from the returned string array:
var x = "FundList[10].Amount";
var num = x.Split('[', ']')[1];
int res = Convert.ToInt32(num);
As its fixed as FundList simply:
int i = int.Parse(x.Substring(9, x.IndexOf(']') - 9));
Maybe something like: Online Demo
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
string text = "FundList[15].Amount";
var result = Convert.ToInt32(Regex.Replace(text, #"[^\d]+",""));
Console.WriteLine("Result is = {0}", result);
}
}
If you prefer LINQ syntax to Regex:
var x = "FundList[10].Amount";
int n = Int32.Parse(new string(x.Where(c => Char.IsDigit(c)).ToArray())); //10
I must profess that i am not very good with Javascript.
I am creating a table using datatables.net
The datatable is populated using a call to a generic handler that will then call the database (in c#) to get values. This is working.
What i'd like to do is use the column re-order functionality. Setting the order is by an array of integers. I'd like those values to be stored in the database and then assign use it. I haven't thought about the saving columns order part first as i want to get the "get" process working first.
In a normal world, the code to set the column re-order is by coding it into the datatables functionlity like:
<script>
$(function () {
var columnOrder = [4, 3, 2, 1, 0, 5];
$("#<%=DT.ClientID%>").dataTable({
dom: 'Rlfrtip',
colReorder: {
order: columnOrder
},
"bProcessing": true,
"bServerSide": true,
"bFilter": false, //Hide the search box
"sPaginationType": "full_numbers",
"sAjaxSource": "../DataHandler/Data.ashx",
So what I'd like to do is to populate the "columnOrder" with values from the database.
i tried using a webmethod and then getting that value by $.ajax({ + Post. This went to my c# code behind method on the default.aspx but returned an empty object. It also seems to populate the datatable first before going into the webmethod so the timing of the call is not correct as well.
QUESTION: I'm scratching my head if I am over-complicating this. All i want is the return an array of integers from a c# server-side method to a javascript variable. Then use this variable to set the order of the column.
Any suggestion on how i can just get an array of integers from c# into a variable is basically what i'd need to get started.
thanks!
All i want is the return an array of integers from a c# server-side method to a javascript variable.
I have a method that return an array of integers, not really an array but it works like one in javascript.
The method is below
[WebMethod]
public static List<int> getAdd_Zip(int ZIP_ID)
{
try
{
BusinessContacts objContacts = new BusinessContacts();
DataTable dtInf = objContacts.getAdd_Zip(ZIP_ID);
List<int> lRes = new List<int>();
if (dtInf.Rows.Count > 0)
{
lRes.Add(Convert.ToInt32(dtInf.Rows[0]["COU_ID"]));
lRes.Add(Convert.ToInt32(dtInf.Rows[0]["STE_ID"]));
lRes.Add(Convert.ToInt32(dtInf.Rows[0]["MUN_ID"]));
}
return lRes;
}
catch (Exception ex)
{
throw ex;
}
}
Note that the method returns a List of integer, I declare a datatable, then I fill that table with another method (this not important), then, I fill the List with 3 values.
So now, I have the next method on javascript
function wsGetAdd_Zip(ZIP_ID) {
var AddZips = new Array();
var params = new Object();
params.ZIP_ID = ZIP_ID;
params = JSON.stringify(params);
$.ajax({
type: "POST",
url: "Contactos.aspx/getAdd_Zip",
data: params,
contentType: "application/json; charset=utf-8",
async: false,
success: function (result) {
AddZips = result.d;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus + ": " + XMLHttpRequest.responseText);
}
});
return AddZips;
}
That method returns the array of integers.
I hope this helps you.
Problem Description
I wanted to ask about how to use a list Exbando Objects in knockout.js,am using Rob Conrey's Massive and all returned results are dynamic, that's fine with me it suits my needs but when it comes to sending results to knockout i just don't know what to do with it.
Goal
Access object properties like obj.Name, obj.Brand etc...
Sample Code
View:
<div data-bind="foreach: Products">
<p>Product name: <strong data-bind="text: Name"></strong></p>
</div>
Controller:
public JsonResult GetProducts()
{
Products products = new Products();
var Model = products.GetAllProducts();
return Json(Model, JsonRequestBehavior.AllowGet);
}
The result of calling GetProducts is:
[[{"Key":"Id","Value":1},{"Key":"Name","Value":"Badass Boots"},{"Key":"Brand","Value":"Nike"},{"Key":"Description","Value":"Super cool boots that can make you fly (Not Really!)."}, etc...]]
Script File:
function ProductListViewModel() {
// Data
var self = this;
self.Products = ko.observableArray([]);
$.getJSON("/Home/GetProducts", function (data) {
self.Products(data);
});
}
JavaScript error on running the application:
Uncaught ReferenceError: Unable to parse bindings. Bindings value: text: Name Message: Name is not defined
Screen Shot 1:
Screen Shot 2:
An ExpandoObject generally speaking is for all intents and purposes, a dictionary. When serialized as JSON here, it is treated as a dictionary and becomes a collection of key/value pairs (not all serializers behave this way, but the one you're using does). It is not an object you can access members by name, you'll have to convert it into a representation where you can (or serialize it as one in the first place).
Doing the conversion is not the worst thing in the world:
function Product(item) {
var self = this;
// assuming item is an array of key/value pairs
ko.utils.arrayForEach(item, function(pair) {
// doesn't necessarily have to be mapped as an observable
self[pair.Key] = ko.observable(pair.Value);
});
}
With this, you can then map the results to your array of products:
$.getJSON("/Home/GetProducts", function (data) {
self.Products(ko.utils.arrayMap(data, function(item) {
return new Product(item);
}));
});
It looks like the problem is because you are trying to set the value of your ko.observableArray to a json array. Not sure that this will work. Typically this is how I would do it:
function ProductListViewModel() {
// Data
var self = this;
self.Products = ko.observableArray([]);
$.getJSON("/Home/GetProducts", function (data) {
ko.utils.arrayForEach(data, function(item) {
self.Products.push({
Name : item.Name
});
});
});
}
Use knockout's arrayForEach function to iterate through your json array, and push each object into your observableArray.
As in your JSON I see the sequence of Key and Value, so you have to specify the filed name which knockout has to query for to get the relative value and put it on the screen.
So change <strong data-bind="text: Name"> to <strong data-bind="text: Key"> and this should work for you.