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.
Related
I'm developing admin dashboard with Vue, Laravel & Axios.
And I have some problems with trying to upload files to api.
I replaced some real data to type of data
On Client-side I have Array of Objects:
[
{
id: random_generated_id,
img: {obj},
img_is_fullwidth: boolean,
site_url: string,
description: string
},
{
id: random_generated_id
img: {obj},
img_is_fullwidth: boolean,
site_url: string,
description: string
}
...
]
Objects can be added to Array:
addObject() {
this.array.push({
id: new Date().valueOf(),
img: null,
img_is_fullwidth: null,
site_url: null,
description: null
})
}
<div v-for="(content, index) in array" :key="content.index">
<input type="file" :ref="'content' + content.id" v-on:change="handleFileUpload(content.id)">
<label class="checkbox">
<input type="checkbox" v-model="content.img_is_fullwidth">
is fullwidth?
</label>
<input type="text" v-model="content.site_url" required>
<input type="text" v-model="content.description" required>
</div>
<button #click.prevent="addContent">Add content</button>
And I'm using random ids to attach image file to object by:
<input class="file-input" type="file" :ref="'content' + content.id" v-on:change="handleFileUpload(content.id)">
handleFileUpload(itemId) {
var itemIndex = this.array.findIndex(i => i.id === itemId)
this.array[itemIndex].img = this.$refs['content' + itemId][0].files[0]
}
So the problem is when I'm trying to post this data to api with axios,
I get error:
Trying to get property 'img' of non-object
It's happened cause I'm using JSON.stringify() and image object transforms to image array:
let fd = new FormData()
fd.append('array', JSON.stringify(this.array))
Part of Laravel Controller:
$array = json_decode($request->array, true);
foreach ($array as $content) {
$newContent = new WorkContent;
$contentImg = $content->img;
$contentName = uniqid();
$contentExt = $contentImg->getClientOriginalExtension();
$contentPath = $contentImg->storeAs('works/'.$request->client.'/'.$request->slug, $contentName.'.'.$contentExt);
$newContent->img_url = $contentPath;
if ($content->img_is_fullwidth == 'true') {
$newContent->img_is_fullwidth = true;
} else if ($content->img_is_fullwidth == 'false') {
$newContent->img_is_fullwidth = false;
}
$newContent->site_url = $content->site_url;
$newContent->description = $content->description;
$newContent->save();
$work->contents()->attach($newContent);
}
So, the question is:
Any ideas how to solve the problem?
Found solution by myself:
$contentArray = json_decode($r->contents, true);
$contentImgs = $r->contentImgs;
$imgIndex = 0;
for ($i = 0; $i < sizeof($contentArray); $i++) {
if($contentArray[$i]['img'] !== null) {
$contentArray[$i]['img'] = $r->contentImgs[$imgIndex];
}
}
foreach ($contentArray as $content) {
$newContent = new WorkContent;
$contentImg = $content['img'];
if ($contentImg !== null) {
$contentName = uniqid();
$contentExt = $contentImg->getClientOriginalExtension();
$contentPath = $contentImg->storeAs('works/'.$r->client.'/'.$r->slug, $contentName.'.'.$contentExt);
$newContent->img_url = $contentPath;
}
if ($content['img_is_fullwidth'] == 'true') {
$newContent->img_is_fullwidth = true;
} else if ($content['img_is_fullwidth'] == 'false') {
$newContent->img_is_fullwidth = false;
}
$newContent->site_url = $content['site_url'];
$newContent->description = $content['description'];
$newContent->work_id = $w->id;
$newContent->save();
}
I want to do autocomplete function for email like this Auto fill email
I have tried this with auto complete email address but failed.
My JS for this code written as follows :
var EmailDomainSuggester = {
domains: ["yahoo.com", "gmail.com", "google.com", "hotmail.com", "me.com", "aol.com", "mac.com", "live.com", "comcast.com", "googlemail.com", "msn.com", "hotmail.co.uk", "yahoo.co.uk", "facebook.com", "verizon.net", "att.net", "gmz.com", "mail.com"],
bindTo: $('#email'),
init: function() {
this.addElements();
this.bindEvents();
},
addElements: function() {
// Create empty datalist
this.datalist = $("<datalist />", {
id: 'email-options'
}).insertAfter(this.bindTo);
// Corelate to input
this.bindTo.attr("list", "email-options");
},
bindEvents: function() {
this.bindTo.on("keyup", this.testValue);
},
testValue: function(event) {
var el = $(this),
value = el.val();
// email has #
// remove != -1 to open earlier
if (value.indexOf("#") != -1) {
value = value.split("#")[0];
EmailDomainSuggester.addDatalist(value);
} else {
// empty list
EmailDomainSuggester.datalist.empty();
}
},
addDatalist: function(value) {
var i, newOptionsString = "";
for (i = 0; i < this.domains.length; i++) {
newOptionsString +=
"<option value='" +
value +
"#" +
this.domains[i] +
"'>";
}
// add new ones
this.datalist.html(newOptionsString);
}
}
EmailDomainSuggester.init();
My HTML code snippet look like below :
<label for="email">Email</label>
<input id="email" name="email" type="email" placeholder="your#email.com">
It doesn't show suggestion when i write.
But it works while i remove character one by one.
IT DOESN'T SHOW SUGGESTIONS WHILE I AM TYPING BUT SHOWS WHEN I REMOVE
CHARACTER ONE BY ONE AFTER '#'
I use a <ListView> within my project, in view's XML file.
ListView has an attribute which invokes a function whenever you scroll down enough to see last item of ListView.
For more explanation: the listview contains a template item which shows two elements, one is <Label> and other one is an <Image>
The problem: is that when I open the application, it loads multiple times.
¿What is the reason and how could it be prevented?
home.xml
<drawer:rad-side-drawer id="drawer">
<drawer:rad-side-drawer.mainContent>
<!-- Home page contents -->
<stack-layout loaded="contentLoaded">
<ListView items="{{ photoList }}" id="photoList" row="1" colSpan="2" loadMoreItems="loadMorePhotos">
<ListView.itemTemplate>
<GridLayout columns="*, auto" rows="auto,*">
<Label row="0" imageid="{{id}}" text="{{title}}"/>
<Image row="1" stretch="fill" src="{{picture}}"/>
</GridLayout>
</ListView.itemTemplate>
</ListView>
</stack-layout>
</drawer:rad-side-drawer.mainContent>
<drawer:rad-side-drawer.drawerContent>
<widgets:drawer-content />
</drawer:rad-side-drawer.drawerContent>
drawer-content.xml
<grid-layout class="drawer-content">
<stack-layout>
<!-- <label text="Home" tap="navigate" class="{{ selectedPage == 'home' ? 'selected' : '' }}" /> -->
<ListView items="{{ menuList }}" id="menuList" row="1" colSpan="2">
<ListView.itemTemplate>
<GridLayout columns="*, auto">
<Label text="{{ title }}" galleryid="{{id}}" tap="loadPhotos"/>
</GridLayout>
</ListView.itemTemplate>
</ListView>
</stack-layout>
</grid-layout>
home.js
var MenuViewModel = require("../../shared/view-models/menu-view-model");
var PhotoViewModel = require("../../shared/view-models/photo-view-model");
var LoadingIndicator = require("nativescript-loading-indicator").LoadingIndicator;
var BasePage = require("../../shared/BasePage");
var observableModule = require("data/observable")
var ObservableArray = require("data/observable-array").ObservableArray;
var topmost = require("ui/frame").topmost;
var loader = new LoadingIndicator();
var loading_options = {
message: 'دریافت اطلاعات ...',
progress: 1,
android: {
indeterminate: false,
cancelable: false,
progressStyle: 0,
secondaryProgress: 1
},
ios: {
details: "",
square: false,
margin: 10,
dimBackground: true,
color: "#4B9ED6",
mode: 0 // indeterminate
}
};
var menuList = new MenuViewModel([]);
var photoList = new PhotoViewModel([]);
var current_gallery_id = 1;
var current_page = 1;
var isLoading = false;
var pageData = new observableModule.fromObject({
menuList: menuList,
photoList: photoList,
page_title: 'آلبوم عکس',
current_gallery_id: current_gallery_id,
current_page: current_page,
});
var HomePage = function () {
};
HomePage.prototype = new BasePage();
HomePage.prototype.constructor = HomePage;
// Place any code you want to run when the home page loads here.
HomePage.prototype.contentLoaded = function (args) {
}
HomePage.prototype.pageLoaded = function (args) {
page = args.object;
page.bindingContext = pageData;
loader.show(loading_options);
menuList.empty();
menuList.load().then(function () {
loader.hide();
});
};
HomePage.prototype.loadPhotos = function (args) {
var gallery_id = args.object.galleryid.toString();
photoList.empty();
page.getViewById("drawer").toggleDrawerState();
if (current_gallery_id != gallery_id) {
current_gallery_id = gallery_id;
current_page = 1;
console.log("Gallery Changed to : " + current_gallery_id);
}
loader.show(loading_options);
photoList.load(gallery_id, current_page).then(function () {
current_page++;
console.log("Page Changed To : " + current_page);
loader.hide();
return;
});
}
HomePage.prototype.loadMorePhotos = function (args) {
var gallery_id = current_gallery_id;
loader.show(loading_options);
photoList.load(gallery_id, current_page).then(function () {
current_page++;
console.log("Page Changed To : " + current_page);
console.log("Gallery is : " + gallery_id);
loader.hide();
});
}
module.exports = new HomePage();
Debug Console
Try to use a timeoutto prevent loadMorePhotos from being called too many times..
var timeout = setTimeout(loadMorePhotos, 100);
clearTimeout(timeout);
In your case :
function getMorePhotos(){
var gallery_id = current_gallery_id;
loader.show(loading_options);
photoList.load(gallery_id, current_page).then(function () {
current_page++;
console.log("Page Changed To : " + current_page);
console.log("Gallery is : " + gallery_id);
loader.hide();
});
};
HomePage.prototype.loadMorePhotos = function (args) {
var timeout = setTimeout(getMorePhotos, 100);
clearTimeout(timeout);
}
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.
I am kind of new to API's and I have the hang of some of it, but not quite all of it yet. When I type in a tag, such as "HTML" or "JavaScript", I am trying to write a program that will give me the top answerers for that tag. When I type in my result, it says "20 results for undefined," so for some reason, I don't think my code is "communicating" propertly.
I think it has to do with my "Tagged: answered" part, but I'm not sure. What do you guys think?
HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Stack Overflow AJAX Demo</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div class="container">
<div class="intro">
<div class="left stack-image"></div>
<div class="explanation">
<h1>StackOverflow Reputation Builder</h1>
<p>This app lets you search by topic for unanswered questions on Stack Overflow to help you build your reputation. Find unanswered questions for a topic you know about, write quality answers, and watch your reputation go up.</p>
<p>Sometimes, you also need some inspiration. This page also lets you search for the top answerers for a tag. If you want to rise to the top ranks for a topic, see how many reputation points you'll need to aim for!</p>
</div>
</div>
<hr>
<div class="stack">
<h3>Get Unanswered Questions</h3>
<p>Find unanswered questions by tag. For multiple tags, use a semi-colon to separate.</p>
<form class="unanswered-getter" onsubmit="return false;">
<input type="text" placeholder='e.g., "HTML" or "HTML;CSS"' name="tags" size="30" autofocus required>
<input type="submit" value="Submit">
</form>
<h3>View the Top Answerers for a Tag</h3>
<form class="inspiration-getter" onsubmit="return false;">
<input type="text" placeholder="e.g., jQuery" name="answerers" size="30" required>
<input type="submit" value="Submit">
</form>
</div>
<div class="results-container">
<div class="search-results"></div>
<div class="results"></div>
</div>
</div>
<div class="templates hidden">
<dl class="result question">
<dt>Question</dt>
<dd class="question-text"></dd>
<dt>Asked</dt>
<dd class="asked-date"></dd>
<dt>Viewed</dt>
<dd class="viewed"></dd>
<dt>Asker</dt>
<dd class="asker"></dd>
</dl>
<dl class="resultAnswerer">
<dt>Name of Answerer:</dt>
<dd class="answererName"></dd>
<dt>Score:</dt>
<dd class="scoreAmount"></dd>
<dt>Reputation:</dt>
<dd class="reputationAmount"></dd>
</dl>
<div class="error">
<p>Uh-oh! Something went wrong with your request. Here's what we know:</p>
</div>
</div>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="js/app.js"></script>
</body>
</html>
Javascript:
var showQuestion = function(question) {
var result = $('.templates .question').clone();
var questionElem = result.find('.question-text a');
questionElem.attr('href', question.link);
questionElem.text(question.title);
var asked = result.find('.asked-date');
var date = new Date(1000*question.creation_date);
asked.text(date.toString());
var viewed = result.find('.viewed');
viewed.text(question.view_count);
var asker = result.find('.asker');
asker.html('<p>Name: <a target="_blank" '+
'href=http://stackoverflow.com/users/' + question.owner.user_id + ' >' +
question.owner.display_name +
'</a>' +
'</p>' +
'<p>Reputation: ' + question.owner.reputation + '</p>'
);
return result;
};
var topScorers = function(score){
var result = $('.templates .resultAnswerer').clone();
var answererDisplayName = result.find('answererName');
answererDisplayName.text(score.display_name);;
var answererScore = result.find('scoreAmount');
answererScore.text(score.score);
var answererReputation = result.find('reputationAmount');
answererReputation.text(score.reputation);
return result;
}
var showSearchResults = function(query, resultNum) {
var results = resultNum + ' results for <strong>' + query + '</strong>';
return results;
};
var showError = function(error){
var errorElem = $('.templates .error').clone();
var errorText = '<p>' + error + '</p>';
errorElem.append(errorText);
};
var getUnanswered = function(tags) {
var request = { tagged: tags,
site: 'stackoverflow',
order: 'desc',
sort: 'creation'};
$.ajax({
url: "http://api.stackexchange.com/2.2/questions/unanswered",
data: request,
dataType: "jsonp",//use jsonp to avoid cross origin issues
type: "GET",
})
.done(function(result){ //this waits for the ajax to return with a succesful promise object
var searchResults = showSearchResults(request.tagged, result.items.length);
$('.search-results').html(searchResults);
$.each(result.items, function(i, item) {
var question = showQuestion(item);
$('.results').append(question);
});
})
.fail(function(jqXHR, error){
var errorElem = showError(error);
$('.search-results').append(errorElem);
});
};
var getAnswerers = function(answered){
var request = {
tagged: answered,
site: 'stackoverflow',
order: 'desc',
sort: 'score',
};
$.ajax({
url: "http://api.stackexchange.com/2.2/tags/" + answered + "/top-answerers/all_time",
data: request,
dataType: "jsonp",
type: "GET",
})
.done(function(result){
var searchResults = showSearchResults(request.tagged, result.items.length);
$('.search-results').html(searchResults);
$.each(result.items, function(i,item){
var score = topScorers(item);
$('.results').append(score);
});
})
.fail(function(jqXHR, error){
var errorElem = showError(error);
$('.search-results').append(errorElem);
});
}
$(document).ready( function() {
$('.unanswered-getter').submit(function(){
$('.results').html('');
var tags = $(this).find("input[name='tags']").val();
getUnanswered(tags);
});
$('.inspiration-getter').submit(function(){
$('.results').html('');
var answered = $(this).find("input[name='tags']").val();
getAnswerers(answered);
});
});
You're probably calling the getAnswer on submit of a form. Form submission will destroy the Javascript context. To make it work correctly, you should use simple click instead of submit.
Check code below:
<html>
<head>
<script src="jquery-1.10.2.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/stock/modules/exporting.js"></script>
<style>
img {
width: 50px;
height: 50px;
}
</style>
</head>
<body>
<input class="tag"/><button class="search">Search</button>
<div class="search-results"></div>
<script>
var topScorers = function(score){
//Clone result template ode
var result = $('.templates .resultAnswerer').clone();
//set the display name in result
var answererDisplayName = result.find('answererName');
answererDisplayName.text(score.display_name);;
//set the user score amount in result
var answererScore = result.find('scoreAmount');
answererScore.text(score.score);
//set the user reputation amount in result
var answererReputation = result.find('reputationAmount');
answererReputation.text(score.reputation);
return result;
}
var getAnswerers = function(answered){
//the parameters I need to pass in our request to StackOverflow's API
var request = {
tagged: answered,
site: 'stackoverflow',
order: 'desc',
sort: 'score',
};
$.ajax({
//the parameters I need to pass in our request to stackOverFlow's API
//this is the endpoint that I want to use
url: "http://api.stackexchange.com/2.2/tags/" + answered + "/top-answerers/all_time",
data: request,
dataType: "jsonp",
type: "GET",
})
//what the function should do if successful
.done(function(result){
//this gives you the search result description
//var searchResults = showSearchResults(request.tagged, result.items.length);
showResults(result.items);
})
//what the function should do if it fails
.fail(function(jqXHR, error){
$('.search-results').text(JSON.stringify(error));
});
}
function showResults (result) {
var tbody = "";
var thead = "";
var firstEl = result[0];
var propArr = [];
for(var prop in firstEl) {
if(typeof firstEl[prop] !== "object") {
thead += "<th>" + prop + "</th>";
propArr.push(prop);
} else {
var obj = firstEl[prop]
for(var propdeep in obj) {
thead += "<th>" + propdeep + "</th>";
propArr.push(propdeep);
}
}
}
result.forEach(function (rowEl) {
var row = "<tr>";
var currentEl = null;
for(var i = 0; i < propArr.length; i++) {
currentEl = rowEl[propArr[i]];
if(currentEl === undefined) {
currentEl = rowEl["user"][propArr[i]]
}
if(propArr[i] !== "profile_image") {
row += "<td>"+ currentEl + "</td>";
} else {
row += "<td><img src='"+ currentEl + "'></img></td>";
}
}
row += "</tr>";
tbody += row;
});
var table = "<table><thead>" + thead + "</thead><tbody>" + tbody + "</tbody></table>";
$('.search-results').html(table);
}
$('.search').click(function(){
//zero out results if previous search has run
$('.search-results').html('');
//separate line of code
var answered = $(".tag").val();
getAnswerers(answered);
});
</script>
</body>
</html>
*Edit***********************
Since you're using "return false;" in submit of the forms, it's not submitting. That's actually clever as it saves us from having to attach both mouse and key events
There were 3 bugs in the code you posted last.
1> Input text field name is "answerers" but in the submit() function it's used as "tags".
var answered = $(this).find("input[name='tags']").val();
// should be
var answered = $(this).find("input[name='answerers']").val();
2> Data returned from the inspiration-getter form call has different structure than used. Actual structure of each item is as below.
{
post_count: 0,
score: 0,
user: {
display_name: "",
link: "",
profile_image: "",
reputation: 0,
user_id: 0,
user_type: ""
}
}
3> There should be a . (dot) before the selectors used in the topScorers() function.
var answererDisplayName = result.find('answererName'); //should be '.answererName'
answererDisplayName.text(score.display_name);;
var answererScore = result.find('scoreAmount'); //should be '.scoreAmount'
answererScore.text(score.score);
var answererReputation = result.find('reputationAmount'); //should be '.reputationAmount'
That's it,
Here is the working code after corrections,
app.js
var showQuestion = function(question) {
var result = $('.templates .question').clone();
var questionElem = result.find('.question-text a');
questionElem.attr('href', question.link);
questionElem.text(question.title);
var asked = result.find('.asked-date');
var date = new Date(1000*question.creation_date);
asked.text(date.toString());
var viewed = result.find('.viewed');
viewed.text(question.view_count);
var asker = result.find('.asker');
asker.html('<p>Name: <a target="_blank" '+
'href=http://stackoverflow.com/users/' + question.owner.user_id + ' >' +
question.owner.display_name +
'</a>' +
'</p>' +
'<p>Reputation: ' + question.owner.reputation + '</p>'
);
return result;
};
var topScorers = function(item){
var user = item.user;
var result = $('.templates .resultAnswerer').clone();
var answererDisplayName = result.find('.answererName');
answererDisplayName.text(user.display_name);;
var answererScore = result.find('.scoreAmount');
answererScore.text(item.score);
var answererReputation = result.find('.reputationAmount');
answererReputation.text(user.reputation);
return result;
}
var showSearchResults = function(query, resultNum) {
var results = resultNum + ' results for <strong>' + query + '</strong>';
return results;
};
var showError = function(error){
var errorElem = $('.templates .error').clone();
var errorText = '<p>' + error + '</p>';
errorElem.append(errorText);
};
var getUnanswered = function(tags) {
var request = { tagged: tags,
site: 'stackoverflow',
order: 'desc',
sort: 'creation'};
$.ajax({
url: "http://api.stackexchange.com/2.2/questions/unanswered",
data: request,
dataType: "jsonp",//use jsonp to avoid cross origin issues
type: "GET",
})
.done(function(result){ //this waits for the ajax to return with a succesful promise object
var searchResults = showSearchResults(request.tagged, result.items.length);
$('.search-results').html(searchResults);
$.each(result.items, function(i, item) {
var question = showQuestion(item);
$('.results').append(question);
});
})
.fail(function(jqXHR, error){
var errorElem = showError(error);
$('.search-results').append(errorElem);
});
};
var getAnswerers = function(answered){
var request = {
tagged: answered,
site: 'stackoverflow',
order: 'desc',
sort: 'score',
};
$.ajax({
url: "http://api.stackexchange.com/2.2/tags/" + answered + "/top-answerers/all_time",
data: request,
dataType: "jsonp",
type: "GET",
})
.done(function(result){
var searchResults = showSearchResults(request.tagged, result.items.length);
$('.search-results').html(searchResults);
$.each(result.items, function(i,item){
var score = topScorers(item);
$('.results').append(score);
});
})
.fail(function(jqXHR, error){
var errorElem = showError(error);
$('.search-results').append(errorElem);
});
}
$(document).ready( function() {
$('.unanswered-getter').submit(function(){
$('.results').html('');
var tags = $(this).find("input[name='tags']").val();
if(!tags || $.trim(tags) === "") {
alert("input is empty");
} else {
getUnanswered(tags);
}
});
$('.inspiration-getter').submit(function(){
$('.results').html('');
var answered = $(this).find("input[name='answerers']").val();
if(!answered || $.trim(answered) === "") {
alert("input is empty");
} else {
getAnswerers(answered);
}
});
});
I figured out part of what I did wrong.
I had name 'tags" instead of name 'answerers', so part of my problem is fixed.
Now if I get results, it will say "20 results of HTML" or "20 results of CSS" or whatever tag I use.
Now I just need to figure out why all of my results are blank. For some reason, it works for one button, but not the other.
JavaScript:
$('.inspiration-getter').submit(function(){
$('.results').html('');
var answered = $(this).find("input[name='tags']").val();
getAnswerers(answered);
});
HTML:
<form class="inspiration-getter" onsubmit="return false;">
<input type="text" placeholder="e.g., jQuery" name="answerers" size="30" required>
<input type="submit" value="Submit">
</form>