Jquery .autocomplete not working - javascript

I have a jquery autocomplete which is not doing anything. I have used the code from here. It works in their example.
There are some changes... First, array is created from a viewModelList and it works. here is a small part of it:
var suburbs = [
{
id: "17023",
suburb: "Epsom",
postCode: "3551",
state: "VIC"
},
{
id: "17024",
suburb: "Muskerry",
postCode: "3557",
state: "VIC"
}
I have endeavoured to use messages to indicate the respose - what it is but even the messages dont work... I cannot even get the response value..
I created a div below the form for the messages and they work having been tested using a click function.. I did try a ".change" function on the "#Suburbs" id and also got nothing..
Here is the code:
<script>
(function ($) {
$(function () {
var suburbs = [
#for (var i = 0; i < Model.SuburbAndPostcodesList.Count; i++) {
<text>{
id: "#Model.SuburbAndPostcodesList[i].SuburbsAndPostcodesId",
suburb: "#Model.SuburbAndPostcodesList[i].Suburb",
postCode: "#Model.SuburbAndPostcodesList[i].PostCode",
state: "#Model.SuburbAndPostcodesList[i].State.ShortName"
}#(i == Model.SuburbAndPostcodesList.Count - 1 ? "" : ",")</text>
}
];
$("#Suburb").autocomplete({
source: function (req, responseFn) {
addMessage("search on: '" + req.term + "'<br/>");
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp("^" + re, "i");
var a = $.grep(suburbs, function (item , index) {
//addMessage(" sniffing: '" + item + "'<br/>");
return matcher.test(item.suburb);
});
addMessage("Result: " + a.length + " items<br/>");
responseFn(a);
},
select: function (value, data) {
if (typeof data == "undefined") {
addMessage('You selected: ' + value + "<br/>");
} else {
addMessage('You selected: ' + data.item.value + "<br/>");
}
}
});
function addMessage(msg) {
$('#msgs').append(msg);
}
});
});
</script>
The id "#Suburb" is correct and worked for a simple version of .autocomplete.
EDIT: here is page code for the javascript.. Hope this is what you were after..
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="/js/site.js?v=EWaMeWsJBYWmL2g_KkgXZQ5nPe-a3Ichp0LEgzXczKo"></script>
<script src="/lib/jquery/dist/jquery.min.js"></script>
<script src="/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script src="/lib/jquery-ui/jquery-ui.js"></script>
<script>
(function ($) {
$(function () {
var suburbs = [
{
id: "17023",
suburb: "Epsom",
postCode: "3551",
state: "VIC"
},
{
id: "17024",
suburb: "Muskerry",
postCode: "3557",
state: "VIC"
},
...
{
id: "17055",
suburb: "Bonnet Hill",
postCode: "7053",
state: "TAS"
},
{
id: "17056",
suburb: "Wellington Park",
postCode: "7054",
state: "TAS"
}
];
$("#Suburb").autocomplete({
source: function (req, responseFn) {
addMessage("search on: '" + req.term + "'<br/>");
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp("^" + re, "i");
var a = $.grep(suburbs, function (item , index) {
//addMessage(" sniffing: '" + item + "'<br/>");
return matcher.test(item.suburb);
});
addMessage("Result: " + a.length + " items<br/>");
responseFn(a);
},
select: function (value, data) {
if (typeof data == "undefined") {
addMessage('You selected: ' + value + "<br/>");
} else {
addMessage('You selected: ' + data.item.value + "<br/>");
}
}
});
function addMessage(msg) {
$('#msgs').append(msg);
}
});
});
</script>
EDIT2: Here is the div element "suburb" as I think its probably a good idea to see what the autocomplete is working on.
<div class="form-group">
<label class="col-md-2 control-label" for="Suburb">Suburb:</label>
<div class="col-md-10">
<input class="form-control" type="text" data-val="true" data-val-required="A suburb name is required" id="Suburb" name="Suburb" value="Eaglehawk" />
<span class="text-danger field-validation-valid" data-valmsg-for="Suburb" data-valmsg-replace="true" />
</div>
</div>

Okay, a few things:
first: your jQuery .ready() function isn't running at all. You are combining several shorthand and advanced techniques, and they are not working. (More details on this in the comments below) Until you can do some research and get the concepts down, probably better to use the long-hand method, and just do
$(document).ready(function() {
});
Second: when you do $('#Suburb'), that means you have to have an element with id="Suburb" someplace in your document. Your input didn't have that.
Third: your a array that you are returning is an array of objects which your autocomplete won't recognize. You either need to return an array of strings, or an array of objects in this format: { label: "Choice1", value: "value1" }. The easiest way to accomplish this was just to add .map into your existing code, right after the .grep:
source: function (req, responseFn) {
addMessage("search on: '" + req.term + "'<br/>");
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp("^" + re, "i");
var a = $.grep(suburbs, function (item , index) {
return matcher.test(item.suburb);
});
a = $.map(a, function(x){
return x.suburb;
});
addMessage("Result: " + a.length + " items<br/>");
responseFn(a);
},
That being said, I have made some mods to your code (making some assumptions) and here is a working fiddle. Sorry, I had already started working on my own fiddle by the time you added yours. It was easier to just continue with the fiddle that I created than it was to modify yours.

Related

Error trying to migrate to Bing Maps v8 from v7

I'm trying to migrate from Bing Maps v7 to v8 and I've run into an error. It's odd because the error changes slightly if I try async vs synchronously. I've scoured StackOverFlow and Google but can't seem to nail this one down.
If I try async, the error I get is:
Uncaught ReferenceError: Microsoft is not defined
If I try synchronously, the error I get is:
Uncaught TypeError: cannot read property 'road' of undefined
Like many others I've found reference to, I have used the Bing developer sight and the code works fine, no problems. On my site, not so much. Our site is Asp.net MVC based.
I found a page somewhere that suggested I put the following code in the head section and I've done that too.
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Nothing I do seems to work. Here's my code pertaining to the map:
<div style="float:left" id='myMap'></div>
<script type="text/javascript" src='https://www.bing.com/api/maps/mapcontrol?callback=getMap' async defer></script>
function getMap() {
var mapOptions = { credentials: 'MY ACCESS KEY',
height: 600,
width: 650,
mapTypeId: Microsoft.Maps.MapTypeId.Road,
showMapTypeSelector: true,
enableClickableLogo: false,
enableSearchLogo: false
};
map = new Microsoft.Maps.Map(document.getElementById('myMap'), mapOptions);
};
I've tried commenting out almost the whole page just to see if I could get something to show up and I still get the same error messages. Clearly I'm missing something for reference but can't seem to figure it out. Thanks in advance.
Here's the complete cshtml file code if that helps:
#model EspexWeb.Models.JobMapInformation
#using EspexWeb.Models
#{
ViewBag.Title = "Map Information";
}
<div class="pagebanner">Job Map</div>
#if (AccessHelper.IsMember("Administrators,Sales,Contact_Admin,Jobsite_Super"))
{
<div style="float:left; cursor: pointer;" data-bind="click: saveLocation"><img title="Save changes." src="#Url.Content("~/Content/images/save.png")" alt="Save" /></div>
}
<div style="float:left; cursor: pointer;" data-bind="click: printdiv, visible: tabID() == 'ui-id-2'"><img title="Print Route." src="#Url.Content("~/Content/images/print_48.png")" alt="Print" /></div>
<div style="float:left; cursor: pointer;" data-bind="click: findLocation, visible: tabID() == 'ui-id-1'"><img title="Find Location." src="#Url.Content("~/Content/images/find_location_48.png")" alt="Find" /></div>
<div style="float:left; cursor: pointer;" data-bind="click: getDirections, visible: tabID() == 'ui-id-2'"><img title="Map Route." src="#Url.Content("~/Content/images/route_48.png")" alt="Route" /></div>
<div style="float:left; margin-left:40px">
<span class="label3">Job Number:</span><span class="value3 spanlink" data-bind="click: backToJob">#Model.JobNumber</span><span style="margin-left:25px" class="label3">Job Name:</span><span class="value3 spanlink" data-bind="click: backToJob">#Model.JobName</span>
</div>
#if (ViewBag.ReturnUrl != null)
{
<div data-bind="click: backToValidation" style="float:right; cursor: pointer"><img title="Click here to return to Validation." src="#Url.Content("~/Content/images/Validate_48.png")" alt="Validation" /></div>
}
<div class="clear"></div>
<div id="errorMessages" class="validation-summary-errors"></div>
<div id="tabs">
<ul>
<li><span>Address</span></li>
<li><span>Directions</span></li>
</ul>
<div id="tabs-1">
<div style="float:left; margin-right:10px; width:220px; min-height: 100px;">
<div class="busyindicator"></div>
<form id="findlocation" action="">
<div id="address">
<div id="location">
<div>Street</div>
<input id='street' name='street' style="width:200px" data-bind="value: street" />
<div>City</div>
<input id='city' name='city' style="width:200px" data-bind="value: city" />
<div>State</div>
<input id='state' name='state' style="width:100px" data-bind="value: state" />
<div>Zip Code</div>
<input id='zipcode' style="width:100px" data-bind="value: zipcode" />
<div>County</div>
<input id='county' style="width:200px" data-bind="value: county" />
<div>Country</div>
<input id='country' style="width:200px" data-bind="value: country" />
<div>Longitude</div>
<input id='longitude' style="width:200px" readonly="readonly" data-bind="value: longitude" />
<div>Latitude</div>
<input id='latitude' style="width:200px; display: block;" readonly="readonly" data-bind="value: latitude" />
</div>
<div id="instructions" style="margin-top: 10px">
<div>Special Instructions</div>
<textarea id="specialinstructions" rows="10" cols="25" data-bind="value: specialInstructions"></textarea>
</div>
</div>
</form>
<div id="directions" style="display: none">
<div>Street</div>
<input id='startstreet' style="width:200px" />
<div>City</div>
<input id='startcity' style="width:200px" />
<div>State</div>
<input id='startstate' style="width:100px" />
</div>
</div>
<div style="float:left" id='myMap'></div>
<div class="clear"></div>
</div>
</div>
<div id="output"></div>
<script type="text/javascript" src='https://www.bing.com/api/maps/mapcontrol?callback=getMap' async defer></script>
<script type="text/javascript">
var map = null;
var query;
var start;
var viewModel = {
id: '#Model.ID',
jobNumber: '#Model.JobNumber',
jobName: '#Model.JobName',
street: ko.observable('#Model.Street'),
city: ko.observable('#Model.City'),
county: ko.observable('#Model.County'),
state: ko.observable('#Model.State'),
country: ko.observable('#Model.Country'),
zipcode: ko.observable('#Model.ZipCode'),
longitude: ko.observable('#Model.Longitude'),
latitude: ko.observable('#Model.Latitude'),
specialInstructions: ko.observable(#(Html.Raw(Json.Encode(Model.SpecialInstructions)))),
returnUrl: '#Html.Raw(ViewBag.ReturnUrl)',
tabID: ko.observable(0)
}
viewModel.showDirections = function () {
if ($("#directions").is(":hidden")) {
$("#address").slideUp("slow", function () {
$("#directions").slideDown("slow");
});
}
};
viewModel.showAddress = function () {
if ($("#address").is(":hidden")) {
$("#directions").slideUp("slow", function () {
$("#address").slideDown("slow");
});
}
};
viewModel.getModelData = function() {
var map = {
ID: viewModel.id,
JobNumber: viewModel.jobNumber,
JobName: viewModel.jobName,
Street: viewModel.street(),
City: viewModel.city(),
State: viewModel.state(),
County: viewModel.county(),
ZipCode: viewModel.zipcode(),
Country: viewModel.country(),
Longitude: viewModel.longitude(),
Latitude: viewModel.latitude(),
SpecialInstructions: viewModel.specialInstructions()};
return ko.toJSON(map);
};
viewModel.backToJob = function () {
location.href = '#Url.Content("~/JobInformation/JobDetail/?id=")' + viewModel.id;
}
viewModel.backToValidation = function () {
location.href = viewModel.returnUrl;
}
viewModel.saveLocation = function () {
//Display busy indicator to show user something is happening on the server
$(".busyindicator").show();
$.ajax({
cache: false,
url: '#Url.Content("~/JobInformation/SaveMap/")',
data: viewModel.getModelData(),
type: "post",
contentType: "application/json",
success: function (result) {
//Allow the user to leave the page without warning
window.onbeforeunload = null;
},
error: function (result) {
alert("The server returned the error code: " + result.status + '\n' + "Message: " + result.statusText + '\n' + result.responseText);
},
complete: function () {
$(".busyindicator").hide();
}
});
};
viewModel.updateInputScreen = function (tabid) {
if (tabid === "ui-id-1") {
viewModel.showAddress();
}
else {
viewModel.showDirections();
}
viewModel.tabID(tabid);
};
function printdiv() {
w = window.open();
//Include the style sheets that format the map directions properly
w.document.write('<link rel="stylesheet" type="text/css" rev="stylesheet" href="http://ecn.dev.virtualearth.net/mapcontrol/v7.0/css/bin/7.0.2011100111334.47/en/mapDirections.css">');
w.document.write('<link rel="stylesheet" type="text/css" rev="stylesheet" href="http://ecn.dev.virtualearth.net/mapcontrol/v7.0/css/bin/7.0.2011100111334.47/en/mapdelay.css">');
w.document.write('<link rel="stylesheet" type="text/css" rev="stylesheet" href="http://ecn.dev.virtualearth.net/mapcontrol/v7.0/css/bin/7.0.2011100111334.47/en/mapcontrol.css">');
w.document.write($('#jobinfo').html());
w.document.write(viewModel.specialInstructions());
w.document.write($('#output').html());
};
function getMap() {
// Set the map and view options, setting the map style to Road and
// removing the user's ability to change the map style
var mapOptions = { credentials: 'MY ACCESS KEY',
height: 600,
width: 650,
mapTypeId: Microsoft.Maps.MapTypeId.Road,
showMapTypeSelector: true,
enableClickableLogo: false,
enableSearchLogo: false
};
map = new Microsoft.Maps.Map(document.getElementById('myMap'), mapOptions);
if (viewModel.longitude().length == 0 || viewModel.longitude() == null) {
getCurrentLocation();
}
else {
setJobPushpinLocation();
}
};
function setJobPushpinLocation() {
var location = new Microsoft.Maps.Location(viewModel.latitude(), viewModel.longitude());
var pushpinOptions = { draggable: true };
var pushpin = new Microsoft.Maps.Pushpin(location, pushpinOptions);
Microsoft.Maps.Events.addHandler(pushpin, 'dragend', endDragDetails);
map.entities.push(pushpin);
map.setView({zoom: 15, center: location });
}
function getCurrentLocation() {
var geoLocationProvider = new Microsoft.Maps.GeoLocationProvider(map);
geoLocationProvider.getCurrentPosition({ showAccuracyCircle: false });
};
function findLocation() {
if ($("#findlocation").valid()) {
var street = document.getElementById("street");
var city = document.getElementById("city");
var state = document.getElementById("state");
query = street.value + ' ' + city.value + ', ' + state.value;
deletePushpin();
map.getCredentials(callSearchService);
window.onbeforeunload = function () { return "You have changed the jobsite location. \r\n If you leave this page the changes will be lost."; };
}
};
function getDirections() {
var street = document.getElementById("startstreet");
var city = document.getElementById("startcity");
var state = document.getElementById("startstate");
start = street.value + ' ' + city.value + ', ' + state.value;
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: directionsModuleLoaded });
};
function deletePushpin() {
for (var i = map.entities.getLength() - 1; i >= 0; i--) {
var pushpin = map.entities.get(i);
if (pushpin instanceof Microsoft.Maps.Pushpin || pushpin instanceof Microsoft.Maps.Polyline) {
map.entities.removeAt(i);
};
}
};
endDragDetails = function (e) {
$(".busyindicator").show();
var loc = e.entity.getLocation();
viewModel.latitude(loc.latitude);
viewModel.longitude(loc.longitude);
map.getCredentials(getAddressByLongLat);
window.onbeforeunload = function () { return "You have changed the jobsite location. \r\n If you leave this page the changes will be lost."; };
};
function getAddressByLongLat(credentials) {
var loc = viewModel.latitude() + ',' + viewModel.longitude();
var searchRequest = 'http://dev.virtualearth.net/REST/v1/Locations/' + loc + '?output=json&jsonp=addressByLongLatCallback&key=' + credentials;
var mapscript = document.createElement('script');
mapscript.type = 'text/javascript';
mapscript.src = searchRequest;
document.getElementById('myMap').appendChild(mapscript)
};
function addressByLongLatCallback(result) {
var output = document.getElementById("output");
if (output) {
while (output.hasChildNodes()) {
output.removeChild(output.lastChild);
}
}
var resultsHeader = document.createElement("h5");
output.appendChild(resultsHeader);
if (result &&
result.resourceSets &&
result.resourceSets.length > 0 &&
result.resourceSets[0].resources &&
result.resourceSets[0].resources.length > 0) {
resultsHeader.innerHTML = "Location Updated " + result.resourceSets[0].resources[0].name;
var countyName = result.resourceSets[0].resources[0].address.adminDistrict2;
if (countyName) {
if (countyName.length !== 0) {
if (countyName.indexOf('Co.') > 0) {
countyName = countyName.substring(0, countyName.length - 4);
};
};
};
viewModel.street(result.resourceSets[0].resources[0].address.addressLine);
viewModel.city(result.resourceSets[0].resources[0].address.locality);
viewModel.state(result.resourceSets[0].resources[0].address.adminDistrict);
viewModel.county(countyName);
viewModel.zipcode(result.resourceSets[0].resources[0].address.postalCode);
viewModel.country(result.resourceSets[0].resources[0].address.countryRegion);
}
else {
if (typeof (response) == 'undefined' || response == null) {
alert("Invalid credentials or no response");
}
else {
if (typeof (response) != 'undefined' && response && result && result.errorDetails) {
resultsHeader.innerHTML = "Message :" + response.errorDetails[0];
}
alert("No results for the query");
}
}
$(".busyindicator").hide();
}
function callSearchService(credentials) {
var searchRequest = 'http://dev.virtualearth.net/REST/v1/Locations/' + query + '?output=json&jsonp=searchServiceCallback&key=' + credentials;
var mapscript = document.createElement('script');
mapscript.type = 'text/javascript';
mapscript.src = searchRequest;
document.getElementById('myMap').appendChild(mapscript)
};
function searchServiceCallback(result) {
var output = document.getElementById("output");
if (output) {
while (output.hasChildNodes()) {
output.removeChild(output.lastChild);
}
}
var resultsHeader = document.createElement("h5");
output.appendChild(resultsHeader);
if (result &&
result.resourceSets &&
result.resourceSets.length > 0 &&
result.resourceSets[0].resources &&
result.resourceSets[0].resources.length > 0) {
resultsHeader.innerHTML = "Found location " + result.resourceSets[0].resources[0].name;
var bbox = result.resourceSets[0].resources[0].bbox;
var viewBoundaries = Microsoft.Maps.LocationRect.fromLocations(new Microsoft.Maps.Location(bbox[0], bbox[1]), new Microsoft.Maps.Location(bbox[2], bbox[3]));
map.setView({ bounds: viewBoundaries });
var location = new Microsoft.Maps.Location(result.resourceSets[0].resources[0].point.coordinates[0], result.resourceSets[0].resources[0].point.coordinates[1]);
var pushpinOptions = { draggable: true };
var pushpin = new Microsoft.Maps.Pushpin(location, pushpinOptions);
var pushpindragend = Microsoft.Maps.Events.addHandler(pushpin, 'dragend', endDragDetails);
map.entities.push(pushpin);
var countyName = result.resourceSets[0].resources[0].address.adminDistrict2;
if (countyName) {
if (countyName.length !== 0) {
if (countyName.indexOf('Co.') > 0) {
countyName = countyName.substring(0, countyName.length - 4);
};
};
};
viewModel.street(result.resourceSets[0].resources[0].address.addressLine);
viewModel.city(result.resourceSets[0].resources[0].address.locality);
viewModel.state(result.resourceSets[0].resources[0].address.adminDistrict);
viewModel.county(countyName);
viewModel.zipcode(result.resourceSets[0].resources[0].address.postalCode);
viewModel.country(result.resourceSets[0].resources[0].address.countryRegion);
viewModel.latitude(location.latitude);
viewModel.longitude(location.longitude);
}
else {
if (typeof (response) == 'undefined' || response == null) {
alert("Invalid credentials or no response");
}
else {
if (typeof (response) != 'undefined' && response && result && result.errorDetails) {
resultsHeader.innerHTML = "Message :" + response.errorDetails[0];
}
alert("No results for the query");
}
}
};
function directionsModuleLoaded() {
// Initialize the DirectionsManager
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
var lat = document.getElementById("latitude");
var long = document.getElementById("longitude");
// Create start and end waypoints
var startWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: start });
var endWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: new Microsoft.Maps.Location(lat.value, long.value) });
directionsManager.addWaypoint(startWaypoint);
directionsManager.addWaypoint(endWaypoint);
// Set request options
directionsManager.setRequestOptions({ distanceUnit: Microsoft.Maps.Directions.DistanceUnit.miles, routeOptimization: Microsoft.Maps.Directions.RouteOptimization.shortestDistance });
// Set the render options
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('output') });
// Specify a handler for when an error occurs
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', displayError);
// Calculate directions, which displays a route on the map
directionsManager.calculateDirections();
};
function displayError(e) {
// Display the error message
alert(e.message);
};
ko.applyBindings(viewModel);
$(document).ready(function () {
$("#tabs").tabs({
activate: function (event, ui) {
viewModel.updateInputScreen(ui.newTab.context.id);
}
});
$("#findlocation").validate(
{
errorLabelContainer: "#errorMessages",
wrapper: "li",
rules: {
street: { required: true },
city: { required: true },
state: { required: true }
},
messages: {
street: { required: "Street is required." },
city: { required: "City is required." },
state: { required: "State is required." }
}
});
getMap();
});
</script>
To anyone who comes looking in the future, what I found is that the div where the map is to post needs to have a Height and Width style defining it.
The error with the async method where Microsoft is undefined will continue to happen, but the map works.
Here's the odd part and I didn't realize this until I started to switch to v8...this error was happening in ver 7 too. In fact until a few days ago, ver 7 was still working using the same code.
A few points:
Your JavaScript to load the map is not in a script tag.
You should consider moving the map script tag below your map load JavaScript, as it is possible that if the map control is cached, it will fire the callback before the GetMap function has been loaded into the page. This often happens if you press the refresh button.
Also, the mapTypeId should be Microsoft.Maps.MapTypeId.road with a small "r" not a capital.
When you have a float style, you have to specify a width/height as their is no way to determine this dynamically.
Width/Height/enableSearchLogo are not map options in V8. This wouldn't cause an issue and would simply be ignored, but something you can remove to simplify your code.

Proper approach for complex / nested JavaScript-object creation within another object

The following code is meant to be a short example for a simple construct of a reusable object. This is a very simple, one level depth object, put as many props and methods as you like and just assign them.
function someDesiredReusableType(optionally, pass, ctor, pars, here) {
//core obj to return
var DesiredTypeCrtor = {
propSkiingLocation: "canada",
OrderTickets: function(optionally){
var tryRoomWView = optionaly;
print(
"Dear " + ctor +", your request for " +
propSkiingLocation + " is now being processed: an " +
tryRoomWView + " request was notified, we understand you have " + pars + " for cross country transportation, confirmation email will be sent " + here + " as soon as we process your order. }
}
};
return DesiredTypeCrtor
}
Here is an example of this use:
var DesrVacSkC = someDesiredReusableType("could really help!",null, "mr. Bean", "my mini", "Fun#bbc.co.uk")
//oh..almost forgot
DesrVacSkC.OrderTickets();
As this imaginative object, is actually not as simple as I did use in my code, it does work as is (didn't try this actual one, as it's just an example.)
But this next setup that is similarly using the same approach is buggy somewhat.
This is an example for an object I have successfully and in a blink of an eye implemented as a nested object using the exact same approach as the buggy object, which I do not understand why they Applied the not with same approach by the browser.
//this is an important one, a smart property / value holder I came up with and does work perfectly, as a nested member.
function Rprp(parVal) {
var cretdprp = {
propVal: parVal,
propValAsint: parseInt(parVal)
};
return cretdprp;
}
But the next one, here below, does not, as it lacks the proper approach for the initialization of ownedFefCollCore
Uncaught TypeError: Cannot read property 'HElmTColl' of undefined
//this is an important one, that was started as a very good one, with adding it to the object below, up until I have added ownedFefCollCore member.
function CreateFileEditForm_Manager() {
//as i do usually base/inner/creator and a return obj
var Repo = {
CsDataLocals:
{
GetCurLastfileId:Rprp($("#HLocModelData_LastFileId").val())
},
FormFldNames:
{ JRdrData_FileName: "JRdrData_FileName" },
//this is my bugg ! with and without new keyword & as function or Object!!
ownedFefCollCore: new FefCollCore(),
//and this is the line that chrome get's is anger on --> all day long
FeFDivWFldsColl: this.ownedFefCollCore.HElmTColl,
FeFDivWFlds_IdColl: this.ownedFefCollCore.HElmT_IdColl,
FeFDivWFldsCollAdd: function (parId, parFefDivWrpDivflds) {
this.ownedFefCollCore.CollAdd(parId, parFefDivWrpDivflds);
},
/ ........
//some more code was removed trying to keep it as short as possible
}
//fefa stands for fileRecord Edit Form , core just says nothing, is there to imply the 'thing' is to be shared between variation of instances from the base object
I found the following approach in my research for less error prone constructs, but even this one does not correct the bug. And it was found among some others, such as this Object.create()
var FefCore = JClassProto({
initialize: function () {
this.HElmTColl = new Array();//was originally [] ...
//i changed because i wanted to eliminate any doubt that it's one of the reasons my code is ... Somewhere undefined , now i know (pretty sure they might be little different but both are ok.) it's not it.
this.HElmT_IdColl = new Array();
this.CollAdd = function (parId, parHElmT) {
this.HElmTColl.push(parHElmT);
this.HElmT_IdColl.push(parId);
}
this.Coll_Remove = function (parHElmT) {
this.HElmTColl.pop(parHElmT);
}
// this is the first move, if a new object(which is an element in the array) about to be created,
// call this to make sure not exist for i create do
this.ElmObjCanCreate = function (parId) {
return this.getIndexOfValuInDivWFldsColl(parId) < 0;
}
this.HElmTColl_FindById = function (parId) {
var collindexofCurFileReadyDivWrpFlds = this.getIndexOfValuInDivWFldsColl(parId);
return this.HElmTColl[collindexofCurFileReadyDivWrpFlds];
}
this.getIndexOfValuInHElmTColl = function (parId) {
return $.inArray(parId, this.HElmT_IdColl);
}
}
});
And last but not least, my original code (right after the attempt to create it as a base /shared object).
function FefCollCore() {
this.Cr = {
HElmTColl: new Array(),
HElmT_IdColl: new Array(),
CollAdd: function (parId, parHElmT) {
this.HElmTColl.push(parHElmT);
this.HElmT_IdColl.push(parId);
},
Coll_Remove: function (parHElmT) {
this.HElmTColl.pop(parHElmT);
},
CollNeedCreate: function (parId) {
return this.getIndexOfValuInDivWFldsColl(parId) < 0;
},
HElmTColl_FindById: function (parId) {
var collindexofCurFileReadyDivWrpFlds = this.getIndexOfValuInDivWFldsColl(parId);
return this.HElmTColl[collindexofCurFileReadyDivWrpFlds];
},
getIndexOfValuInHElmTColl: function (parId) {
return $.inArray(parId, this.HElmT_IdColl);
}
};
return this.Cr;
}
//and this is the line that chrome get's is anger on --> all day long
FeFDivWFldsColl: this.ownedFefCollCore.HElmTColl,
If interpret Question correctly, you could try to set FeFDivWFldsColl as a function that returns this.ownedFefCollCore.HElmTColl
var FefCore = function() {
this.e = new Array();
this.e.push(2);
}
function CreateFileEditForm_Manager() {
var Repo = {
a: 0,
b: 1,
c: new FefCore(),
// set `FeFDivWFldsColl` value as a function
d: function() {
// `this.c` : `new FefCore()` , `this.c.e` : `new Array()`
return this.c.e
}
};
return Repo
}
var Fef = new CreateFileEditForm_Manager();
console.log(Fef.d())
var cont = "...see console";
var DivEmptyhtml = document.createElement('div');
var elmst = document.createElement('style');
function stringcss (){
return ".cssEmptyhtml{ \r\n\tmargin:auto; margin-top:10px; margin-bottom:20px;"+
" text-align:center; top:10px;"+
" width:40%; padding: 5px; height: 100px; " +
"background-color:rgb(96,116,243); "+
"color: #B5fee8; "+
"background-image:" +
" linear-gradient(to right bottom, #2983bC 24%, #284a4b 77%);"+
" box-shadow: 8px 10px 50px 20px rgb(55, 55, 55); "+
" -webkit-border-radius:10px;border-radius:10px; }";
}
//elmst.innerHTML = stringcss();
DivEmptyhtml.innerHTML = cont;
DivEmptyhtml.className = "cssEmptyhtml";
DivEmptyhtml.attributes["id"] ="DivEmptyhtml";
$("head").append(elmst);
$("body").append(DivEmptyhtml);
$(elmst).attr("id","elmst");
//$(".cssEmptyhtml").attr("style",stringcss());
$(elmst).text(stringcss());
var strS, strF, message;
var indx = 123;
var count = 135;
indx = ++count - 1;
var init = true;
//now me
var programSteps = 0;
var starting = "starting";
console.log(starting);
function Log(strLine) {
var d = new Date,
DS = d.getSeconds(),
Dms = d.getMilliseconds().toString();
console.log("[step#" + (++programSteps) + "] " + DS + "." + Dms.substring(0, 2) + "> " + strLine);
}
//...see console
function LogObj(p_type) {
function Fnl_t_t() {
this.obj = "\r\n\t\t";
}
function Fnl_5xt() {
this.obj = "\r\n\t\t\t\t";
}
var obj = {
doNewLineBold: function(boolPrint, value, value2, value3, value4) {
var nlttcopy = this.backnl_t_t.obj;
this._nl_t_t = lnobj1.backnl_5xt.obj+ "|========> [ " + value;
this._nl_t_t += value2 != "" ? " " + value2 : "";
this._nl_t_t += value3 != "" ? " " + value3 : "";
this._nl_t_t += value4 != "" ? " " + value4 : "";
this._nl_t_t += " ] <=============|" + nlttcopy;
if (boolPrint) {
Log(this._nl_t_t);
return "";
} else return this._nl_t_t;
},
doLineBold: function(boolPrint, value, value2, value3, value4) {
var nlttcopy = this.backnl_t_t.obj;
this._nl_t_t = "|========> [ " + value;
this._nl_t_t += value2 != "" ? " " + value2 : "";
this._nl_t_t += value3 != "" ? " " + value3 : "";
this._nl_t_t += value4 != "" ? " " + value4 : "";
this._nl_t_t += " ] <=============|" + nlttcopy;
if (boolPrint) {
Log(this._nl_t_t);
return "";
} else return this._nl_t_t;
},
_type: {
val: p_type,
formated: ""
},
doformatedHeader: function() {
var splts = this._type.val.split(' ');
for (var i = 0; i < splts.length; i++) {
this._type.formated += splts[i] + this.ErowR;
}
return "|========> [ " + this._type.formated +
" ] <=============|" + this.backnl_5xt.obj;
},
doformatedTail: function() {
return this.backnl_5xt.obj + "|========> [ END_ " + this._type.formated + "_END] <=============|" + this.backnl_t_t.obj;
},
_nl_t_t: function() {
return "\r\n\t\t";
},
backnl_5xt: new Fnl_5xt(),
backnl_t_t: new Fnl_t_t(),
ErowR: ">",
nlArowR : new Fnl_5xt().obj + ">"
};
return obj;
}
var lnobj1 = LogObj("listWcounter1() arr"); //create object #1
var lnobj2 = LogObj("listWcounter2() arr"); //make sure #2 is not a-copy
var header1 = lnobj1.doformatedHeader();
var Tail1 = lnobj1.doformatedTail();
var header2 = lnobj2.doformatedHeader();
var Tail2 = lnobj2.doformatedTail();
var nlarowR1 = lnobj1.backnl_5xt.obj + lnobj1.ErowR;
var nlarowR2 = lnobj2.backnl_t_t.obj + lnobj2.ErowR;
Log(header1 + lnobj1.ErowR + " starting1... " + nlarowR1 + " is init1 ok?, and index1 is Ok? " + indx + Tail1);
Log(header2 + lnobj2.ErowR + " starting2... " + nlarowR1 + " is init2 ok?, and index2 is Ok? " + indx + Tail2);
var newbold = lnobj1.doLineBold(0, "a", "b", "c", "d") + lnobj1.backnl_5xt.obj;
Log("newbold looks Like: " + newbold);
lnobj1.doLineBold(1, "A", "B", "C", "D");
lnobj1.doNewLineBold(1, "e", "f", "g", "h");
Log(lnobj1.nlArowR);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

Build up and array with variable property name

My HTML looks like this:
<label data-plural="foos" data-id="1">Foo</label>
<label data-plural="bars" data-id="2">Bar</label>
I have this code:
var commands = new Array();
$('label.ptype').each(function(k,v) {
var category = $(v).data('plural');
var cmd = 'show ' + category;
var id = $(v).data('id');
commands.push({cmd : function() { window.alert(id + " " + category); exploreId(id, category); }});
});
console.log(commands);
I would like to have in the commands array:
[
{ 'show foos': function() { window.alert('1 foos'); exploreId(1, 'foos'); },
{ 'show bars': function() { window.alert('2 bars'); exploreId(2, 'bars'); }
]
But what I am getting is literally
[ { cmd: function() ... }, { cmd: function() ... } ]
So what is a good way to build the desired array?
In ES5, you have to take apart the object construction:
var command = {};
command[cmd] = function() { window.alert(id + " " + category); exploreId(id, category); };
commands.push(command);
In ES2015, you can use [ ] notation in the object initializer:
commands.push({ [cmd] : function() { window.alert(id + " " + category); exploreId(id, category); }});
That new feature ("computed property names") is supported by Firefox and Chrome and Safari, but not Internet Explorer. (It may be in Edge but I can't find anything explicit and I'm too lazy to fire up my VM :)
For simplicity, readability and execution speed, use the [] instead of new Array();.
You can use a temporary object, an push it into commands (Works on Chrome, Firefox and IE):
var commands = [];
$('label').each(function(k,v) {
var category = $(v).data('plural');
var id = $(v).data('id');
var temp = {};
temp['show ' + category] = function() { window.alert(id + " " + category); exploreId(id, category); };
commands.push(temp);
});
console.log(commands);
console.log(commands[0]['show foos']());//run function
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label data-plural="foos" data-id="1">Foo</label>
<label data-plural="bars" data-id="2">Bar</label>
Fiddle: https://jsfiddle.net/ghorg12110/h0ekmreu/

jquery compare elements with serialize

I'm trying to compare the value of a form element with it's default text (set via the title attribute). If the VALUE == TITLE, change the value to a zero length string. However, I can't seem to make it work. I'm sure it's just my lack of experience with Javascript and jQuery. Many thanks.
HTML
<form name="results-form" id="results-form">
<input type="text" name="price-min" class="form-textbox-small no-radius defaultText" data="Minimum" title="Minimum" onchange="UpdateSearch()">
<input type="text" name="price-max" class="form-textbox-small no-radius defaultText" data="Maximum" title="Maximum" onchange="UpdateSearch()">
</form>
Javascript
function updateSearch(){
$.each($("#results-form").serializeArray(),function(){
console.log("value: "+this.value+" data: "+this.data+" title: "+this.title);
if(this.value == this.title){
this.value = '';
}
});
var FormData = $("#results-form :input[value!='']").serialize();
console.log(FormData);
$(".defaultText").blur();
}
$(document).ready(function () {
$(".defaultText").focus(function (srcc) {
if ($(this).val() == $(this)[0].title) {
$(this).removeClass("defaultTextActive");
$(this).val("");
}
});
$(".defaultText").blur(function () {
if ($(this).val() == "") {
$(this).addClass("defaultTextActive");
$(this).val($(this)[0].title);
}
});
$(".defaultText").blur();
});
Console Output
value: 3 data: undefined title: undefined
value: Maximum data: undefined title: undefined
Try this:
var arr = $("#results-form").serializeArray();
$.each(arr, function (i, input) {
var value = input.value;
var $elem = $("[name='" + input.name + "']");
var data = $elem.attr('data');
var title = $elem.attr('title');
console.log("value: " + value + " data: " + data + " title: " + title );
// You can process the parameters here now
});

Using javascript and jquery, to populate related select boxes with array structure

Using answers to this question, I have been able to populate a select box based on the selection of another select box. ( I posted my answer here) Pulling the data from an array structure built server-side, stored in a .js file and referenced in the html page.
Now I would like to add a third select box. If I had 3 sets of data (model, make, options) something like this (pseudo code):
cars : [Honda[Accord[Lx, Dx]], [Civic[2dr, Hatchback]],
[Toyota[Camry[Blk, Red]], [Prius[2dr,4dr]]
Ex: If Honda were selected, the next select box would have [Accord Civic] and if Accord were selected the next select box would have [Lx Dx]
How can I
1) create an array structure to hold the data? such that
2) I can use the value from one select box to reference the needed values for the next select box
Thanks
EDIT
I can create the following, but can't figure out the references in a way that would help populate a select box
var cars = [
{"makes" : "Honda",
"models" : [
{'Accord' : ["2dr","4dr"]} ,
{'CRV' : ["2dr","Hatchback"]} ,
{'Pilot': ["base","superDuper"] } ]
},
{"makes" :"Toyota",
"models" : [
{'Prius' : ["green","reallyGreen"]} ,
{'Camry' : ["sporty","square"]} ,
{'Corolla' : ["cheap","superFly"] } ]
} ] ;
alert(cars[0].models[0].Accord[0]); ---> 2dr
I prefer data structure like this:
var carMakers = [
{ name: 'Honda', models: [
{ name: 'Accord', features: ['2dr', '4dr'] },
{ name: 'CRV', features: ['2dr', 'Hatchback'] },
{ name: 'Pilot', features: ['base', 'superDuper'] }
]},
{ name: 'Toyota', models: [
{ name: 'Prius', features: ['green', 'superGreen'] },
{ name: 'Camry', features: ['sporty', 'square'] },
{ name: 'Corolla', features: ['cheap', 'superFly'] }
]}
];
Given the three select lists with id's: 'maker', 'model' and 'features' you can manipulate them with this (I believe this is pretty self explanatory):
// returns array of elements whose 'prop' property is 'value'
function filterByProperty(arr, prop, value) {
return $.grep(arr, function (item) { return item[prop] == value });
}
// populates select list from array of items given as objects: { name: 'text', value: 'value' }
function populateSelect(el, items) {
el.options.length = 0;
if (items.length > 0)
el.options[0] = new Option('please select', '');
$.each(items, function () {
el.options[el.options.length] = new Option(this.name, this.value);
});
}
// initialization
$(document).ready(function () {
// populating 1st select list
populateSelect($('#maker').get(0), $.map(carMakers, function(maker) { return { name: maker.name, value: maker.name} }));
// populating 2nd select list
$('#maker').bind('change', function() {
var makerName = this.value,
carMaker = filterByProperty(carMakers, 'name', makerName),
models = [];
if (carMaker.length > 0)
models = $.map(carMaker[0].models, function(model) { return { name: model.name, value: makerName + '.' + model.name} });
populateSelect($('#model').get(0), models);
$('#model').trigger('change');
});
// populating 3rd select list
$('#model').bind('change', function () {
var nameAndModel = this.value.split('.'),
features = [];
if (2 == nameAndModel.length) {
var makerName = nameAndModel[0],
carModel = nameAndModel[1],
carMaker = filterByProperty(carMakers, 'name', makerName);
if (carMaker.length > 0) {
var model = filterByProperty(carMaker[0].models, 'name', carModel)
if (model.length > 0)
features = $.map(model[0].features, function(feature) { return { name: feature, value: makerName + '.' + carModel + '.' + feature} })
}
}
populateSelect($('#feature').get(0), features);
})
// alerting value on 3rd select list change
$('#feature').bind('change', function () {
if (this.value.length > 0)
alert(this.value);
})
});
Thanks to the answer from #Marko Dunic, I was able to build an array (data) structure that can be referenced to populate 3 select boxes. I didn't use the implementation code only because I didn't completely understand it...it works as posted. I will come back to this code later as I learn jQuery.
My code is posted below (obviously, your reference to jQuery may be different)
<html><head>
<script language="Javascript" src="javascript/jquery-1.2.6.min.js"></script>
<script type="text/JavaScript">
var cars = [
{ name: 'Honda', models: [
{ name: 'Accord', features: ['2dr', '4dr'] },
{ name: 'CRV', features: ['2dr', 'Hatchback'] },
{ name: 'Pilot', features: ['base', 'superDuper'] }
]},
{ name: 'Toyota', models: [
{ name: 'Prius', features: ['green', 'superGreen'] },
{ name: 'Camry', features: ['sporty', 'square'] },
{ name: 'Corolla', features: ['cheap', 'superFly'] }
]
}
];
$(function() {
var options = '' ;
for (var i = 0; i < cars.length; i++) {
var opt = cars[i].name ;
if (i == 0){ options += '<option selected value="' + opt + '">' + opt + '</option>'; }
else {options += '<option value="' + opt + '">' + opt + '</option>'; }
}
$("#maker").html(options); // populate select box with array
var options = '' ;
for (var i=0; i < cars[0].models.length; i++) {
var opt = cars[0].models[0].name ;
if (i==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
$("#model").html(options); // populate select box with array
var options = '' ;
for (var i=0; i < cars[0].models[0].features.length; i++) {
var opt = cars[0].models[0].features[i] ;
if (i==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
$("#feature").html(options); // populate select box with array
$("#maker").bind("click",
function() {
$("#model").children().remove() ; // clear select box
for(var i=0; i<cars.length; i++) {
if (cars[i].name == this.value) {
var options = '' ;
for (var j=0; j < cars[i].models.length; j++) {
var opt= cars[i].models[j].name ;
if (j==0) {options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
break;
}
}
$("#model").html(options); // populate select box with array
$("#feature").children().remove() ; // clear select box
for(var i=0; i<cars.length; i++) {
for(var j=0; j<cars[i].models.length; j++) {
if(cars[i].models[j].name == $("#model").val()) {
var options = '' ;
for (var k=0; k < cars[i].models[j].features.length; k++) {
var opt = cars[i].models[j].features[k] ;
if (k==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
break;
}
}
}
$("#feature").html(options); // populate select box with array
});
$("#model").bind("click",
function() {
$("#feature").children().remove() ; // clear select box
for(var i=0; i<cars.length; i++) {
for(var j=0; j<cars[i].models.length; j++) {
if(cars[i].models[j].name == this.value) {
var options = '' ;
for (var k=0; k < cars[i].models[j].features.length; k++) {
var opt = cars[i].models[j].features[k] ;
if (k==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
break ;
}
}
}
$("#feature").html(options); // populate select box with array
});
});
</script>
</head> <body>
<div id="selection">
<select id="maker"size="10" style="{width=75px}"></select>
<select id="model" size="10" style="{width=75px}"></select>
<select id="feature" size="10"style="{width=75px}"></select>
</div></body></html>
I really liked the solution by #Marko Dunic, but it didn't meet my needs for attaching IDs to the options. Once I attached the IDs, I realized that I could make the JS code even smaller and simpler. My solution is designed for when the data comes from a relational database, and the JSON input data retains the relational structure with Primary/Foreign Keys. Here is the JSON data:
<html lang="en">
<head>
<title>Populate a select dropdown list with jQuery - WebDev Ingredients</title>
<script type="text/javascript" src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
var types = [
{ typeID: 1, name: 'Domestic'},
{ typeID: 2, name: 'Import'},
{ typeID: 3, name: 'Boat'}
]
var makes = [
{ typeID: 1, makeID: 1, name: 'Chevy'},
{ typeID: 1, makeID: 2, name: 'Ford'},
{ typeID: 1, makeID: 3, name: 'Delorean'},
{ typeID: 2, makeID: 4, name: 'Honda'},
{ typeID: 2, makeID: 5, name: 'Toyota'},
{ typeID: 2, makeID: 6, name: 'Saab'}
]
var model = [
{ makeID: 1, modelID: 1, name: 'Camaro'},
{ makeID: 1, modelID: 2, name: 'Chevelle'},
{ makeID: 1, modelID: 3, name: 'Nova'},
{ makeID: 2, modelID: 4, name: 'Focus'},
{ makeID: 2, modelID: 5, name: 'Galaxie'},
{ makeID: 2, modelID: 6, name: 'Mustang'},
{ makeID: 4, modelID: 7, name: 'Accord'},
{ makeID: 4, modelID: 8, name: 'Civic'},
{ makeID: 4, modelID: 9, name: 'Odyssey'},
{ makeID: 5, modelID: 10, name: 'Camry'},
{ makeID: 5, modelID: 11, name: 'Corolla'}
]
//
// Put this in a stand alone .js file
//
// returns array of elements whose 'prop' property is 'value'
function filterByProperty(arr, prop, value) {
return $.grep(arr, function (item) { return item[prop] == value });
}
// populates select list from array of items given as objects: { name: 'text', value: 'value' }
function populateSelect(el, items) {
el.options.length = 0;
if (items.length > 0)
el.options[0] = new Option('please select', '');
$.each(items, function () {
el.options[el.options.length] = new Option(this.name, this.value);
});
}
// initialization
$(document).ready(function () {
// populating 1st select list
populateSelect($('#sType').get(0), $.map(types, function(type) { return { name: type.name, value: type.typeID} }));
// populating 2nd select list
$('#sType').bind('change', function() {
var theModels = filterByProperty(makes, 'typeID', this.value);
populateSelect($('#sMake').get(0), $.map(theModels, function(make) { return { name: make.name, value: make.makeID} }));
$('#sMake').trigger('change');
});
// populating 3nd select list
$('#sMake').bind('change', function() {
var theSeries = filterByProperty(model, 'makeID', this.value);
populateSelect($('#sModel').get(0), $.map(theSeries, function(model) { return { name: model.name, value: model.modelID} }));
});
});
</script>
</head>
<body>
Enter values, click submit, and look at the post parameters
<form method="get" action="index.php">
<div id="selection">
<select id="sType" name="type_id" style="{width=75px}"></select>
<select id="sMake" name="make_id" style="{width=75px}"></select>
<select id="sModel" name="model_id" style="{width=75px}"></select>
</div>
<input type="submit">
</form>
</body>
</html>
Notice that my solution shifts the functionality so that Make-Model are the 2nd and 3rd text boxes, and Type ( domestic, import, boat, etc. ) are the 1st level. I got the boilerplate JS down to 23 lines (less comments) while retaining good formatting.
The JSON data is very easy to render from SQL queries, which are cached in java Lists on init because the Type-Make-Model rarely change. I don't use any dynamic AJAX because that complicates the architecture, and I have a relatively small list of available values, so I just send it at the page request.
"Solutions should be a simple as possible, but no simpler" - A. Einstein
You should take a look here for select box manipulation.
For what you want, i think JSON will do the right job for you.
Anyhow, if i were you, i will do this way:
When I change first select, i do an ajax request. With ajax response, i will populate the second box. Same for second box and there you have the third box populated with right data.

Categories