Are the yahoo.finance related data api's change (YQL Console)? - yql

I am trying to use yql for yahoo financial data. I checked the Show Community Table on the YQL console to see the database under the Yahoo tag.
I can see the tables under it but i am not getting results
here it is as follows:::
select * from yahoo.finance.analystestimate where symbol in ('YHOO')
{
"query": {
"count": 1,
"created": "2016-03-28T10:25:01Z",
"lang": "en-US",
"diagnostics": {
"url": [
{
"execution-start-time": "1",
"execution-stop-time": "767",
"execution-time": "766",
"content": "http://www.datatables.org/yahoo/finance/yahoo.finance.analystestimate.xml"
},
{
"execution-start-time": "771",
"execution-stop-time": "1821",
"execution-time": "1050",
"content": "http://finance.yahoo.com/q/ae?s=YHOO"
}
],
"publiclyCallable": "true",
"javascript": {
"execution-start-time": "769",
"execution-stop-time": "1823",
"execution-time": "1054",
"instructions-used": "5139",
"table-name": "yahoo.finance.analystestimate"
},
"user-time": "1824",
"service-time": "1806",
"build-version": "0.2.842"
},
"results": {
"results": {
"symbol": "YHOO"
}
}
}
}
here results are shown as empty ..
Has something changed? How can I find out what happened?
Is there an alternative solution I can use to obtain this data?

The JS the developer used to create the table us no longer working. This is it partially formatted. You can see that he's grabbing the page and then screen scraping it.
function getelement(row) {
if (row.hasOwnProperty("p")) return (row.p.text());
return (row.font.text());
} // Setup Query from finance.yahoo.com
var url = "http://finance.yahoo.com/q/ae?s=" + symbol;
var restquery = y.rest(url);
var rawresult = restquery.accept("text/html").get().response;
var aequery = y.xpath(rawresult, "//table[#class='yfnc_tableout1']/tr[count(td)=0]/parent::*|" + "//table[#class='yfnc_tableout1']/tr/td/table");
// Process Results
var aedata = < results symbol = {
symbol
} > < /results>; var i = 0; while(i < aequery.length()) { var table = aequery[i]; var thead = table.tr[0]; var tname = thead.th[0].strong.text().toString().replace(/ / g,
"");
var fname1 = thead.th[1].p.text().toString().replace(/\n.*/, "");
var fname2 = thead.th[2].p.text().toString().replace(/\n.*/, "");
var fname3 = thead.th[3].p.text().toString().replace(/\n.*/, "");
var fname4 = thead.th[4].p.text().toString().replace(/\n.*/, "");
fname1 = fname1.replace(/[\s\.]+/g, "").replace(/\&/, "");
fname2 = fname2.replace(/[\s\.]+/g, "").replace(/\&/, "");
fname3 = fname3.replace(/[\s\.]+/g, "").replace(/\&/, "");
fname4 = fname4.replace(/[\s\.]+/g, "").replace(/\&/, "");
var tblval = < {
tname
} > < /{tname}>; var j = 1; while(j < table.tr.length()) { var row = table.tr[j].td; var rname = row[0].p.text().toString().replace(/ [\s\.] + /g, ""); rname = rname.replace(/\ (.*\) / g,
"").replace(/\%/, "").replace(/^(\d)/, "_$1");
rname = rname.replace(/\//, "");
var rval1 = getelement(row[1]);
var rval2 = getelement(row[2]);
var rval3 = getelement(row[3]);
var rval4 = getelement(row[4]);
tblval.appendChild( < {
rname
} > < {
fname1
} > {
rval1
} < /{fname1}> <{fname2}>{rval2}</ {
fname2
} > < {
fname3
} > {
rval3
} < /{fname3}> <{fname4}>{rval4}</ {
fname4
} > < /{rname}>); j = j + 1; } aedata.appendChild(tblval); i = i + 1; }
// Return aedata strucuture
response.object = aedata;

Yes, the HTML structure for finance.yahoo.com has been changed somewhere in beginning of 2015, so YQL table implementation needs updating.
Please check the following GH pull requests which aims to fix the current outstanding issues:
GH-449: Update yahoo.finance.analystestimate.xml to new HTML structure
GH-457: Update yahoo.finance.analystestimate.xml
They're bit in overlap, so you may test them both (preferably check the first one).
Or you can check my fork of yql-tables (which consist loads of other fixes as well) where I've merged this PR into it, so find updated yahoo.finance.analystestimate.xml in here, the other one doesn't merge on top of the other one.

Related

More than 100 points and one polyline, Google Maps v3

I'm working with google maps api v3 and I'm trying to use snap to road with more than 100 points but in addition end up with just one polyline with the whole route that I can put a small animation. The view is a html.erb.
var apiKey = any_key;
var map = handler.getMap();
var drawingManager;
var placeIdArray = [];
var snappedCoordinates = [];
var path = <%= raw(#locations) %>
var markers = <%= raw(#markers) %>
var centerOn = path[0].split(',');
function breadCrumbsGrapher(path) {
handler.removeMarkers(Gmaps.store.markers);
for(var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
var divided = handlePath(path);
if (typeof divided[0] == 'object') {
for(var i = 0; i < divided.length; i++) {
runSnapToRoad(divided[i]);
}
} else {
runSnapToRoad(path);
}
}
function waypointsLimiter(path) {
var path_loc_size = path.length;
var limited = [];
if(path_loc_size > 30) {
var stepper = Math.ceil(path_loc_size/30);
for(var i = stepper; i < path_loc_size; i += stepper) {
limited.push(path[i]);
}
if(limited.indexOf(path[path_loc_size-1]) == -1) {
limited.push(path[path_loc_size-1]);
}
} else {
limited = path;
}
return limited;
}
function handlePath(path) {
var i = 0;
var j = path.length;
if (j > 100) {
var newArray = [],
chunk = j/2;
if (j >= 200) {
chunk = j/3;
} else if (j >= 300) {
chunk = j/4;
} else if (j >= 400) {
chunk = j/5;
} else if (j >= 500 ) {
chunk = j/6;
} else if (j >= 600) {
chunk = j/7;
} else if (j >= 700 || j <= 799) {
chunk = j/8;
} else {
alert('La ruta no puede ser mostrada');
}
for (i, j; i < j; i+=chunk) {
newArray.push(path.slice(i,i+chunk+1));
}
return newArray;
} else {
return path;
}
}
// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad(path) {
var path = path.join('|');
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: path,
}, function(data) {
processSnapToRoadResponse(data);
drawSnappedPolyline();
});
}
// Store snapped polyline returned by the snap-to-road service.
function processSnapToRoadResponse(data) {
snappedCoordinates = [];
placeIdArray = [];
for (var i = 0; i < data.snappedPoints.length; i++) {
var latlng = new google.maps.LatLng(
data.snappedPoints[i].location.latitude,
data.snappedPoints[i].location.longitude);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId);
}
}
// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
var symbol = {
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
scale: 3,
strokeColor: '#3B16B3'
};
var snappedPolyline = new google.maps.Polyline({
path: snappedCoordinates,
strokeColor: '#E51E25',
strokeWeight: 3,
icons: [{
icon: symbol,
offset: '0%'
}]
});
snappedPolyline.setMap(map);
animate(snappedPolyline);
zoomToObject(snappedPolyline);
polylines.push(snappedPolyline);
}
function zoomToObject(obj){
var bounds = new google.maps.LatLngBounds();
var points = obj.getPath().getArray();
for (var n = 0; n < points.length ; n++){
bounds.extend(points[n]);
}
map.fitBounds(bounds);
}
function animate(line) {
var count = 0;
window.setInterval(function() {
count = (count + 1) % 600;
var icons = line.get('icons');
icons[0].offset = (count / 6) + '%';
line.set('icons', icons);
}, 70);
}
breadCrumbsGrapher(path);
Also I've tried declaring a variable outside so I can concat all of the coordinates and generate a polyline with it but doesn't seem to work. Actualy that big array ends up being of 2000+ points.
The result that I have with the provided code
After all of that the issue is that I don't know how to merge the polylines to have just one line and being able to animate just that one line. If there's more than 100 coordinates I plot more polylines. In the image you can see that there's 3 icons (one for each polyline) and I need just to draw one line and have 1 icon.
To reproduce the issue just add a key and if you want use this set of coordinates:
https://drive.google.com/file/d/1jLb7Djv5DiSdR3k4QZRSatXBwrohlxcI/view?usp=sharing
function breadCrumbsGrapher(path) {
//mapMarkers();
snappedCoordinates = [];
handler.removeMarkers(Gmaps.store.markers);
for(var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
var divided = handlePath(path);
if (typeof divided[0] == 'object') {
for(var i = 0; i < divided.length; i++) {
runSnapToRoad(divided[i]);
}
} else {
runSnapToRoad(path);
}
console.log(snappedCoordinates);
drawSnappedPolyline();
}
function runSnapToRoad(path) {
var path = path.join('|');
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: path,
}, function(data) {
processSnapToRoadResponse(data);
//drawSnappedPolyline();
});
}
I've changed the code but it doesn't work, even though I end up with a 2,557 coordinates array.
I've tried also tried this thinking that this could give me the time to have all coordinates:
async function breadCrumbsGrapher(path) {
//mapMarkers();
snappedCoordinates = [];
handler.removeMarkers(Gmaps.store.markers);
for(var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
var divided = handlePath(path);
if (typeof divided[0] == 'object') {
for(var i = 0; i < divided.length; i++) {
await runSnapToRoad(divided[i]);
}
} else {
await runSnapToRoad(path);
}
console.log(snappedCoordinates);
drawSnappedPolyline();
}
and:
async function runSnapToRoad(path) {
var path = path.join('|');
await $.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: path,
}, function(data) {
processSnapToRoadResponse(data);
});
}
Thank you in advance.
You are using $.get() to query the Roads API which is an asynchronous call so when you call drawSnappedPolyline() from within your breadCrumbsGrapher function, you most probably don't (yet) have all coordinates in return from your AJAX call(s).
If you have 550 coordinates in your original path, you then know you must call the Roads API 6 times (5 times with 100 points + 1 time with 50 points). You should then be able to set a counter somewhere, to only draw your (complete) Polyline, once you got your 6 responses from the Roads API.
Or you could base that on the length of your final array (compared to the original path) although I don't know what would happen in case some points can't be "snapped".

How to create entry for 2 or more entity sets via OdataModel.create in UI5

I have a Odata service with 4 entity types - Address, CC, Header, Item, Comments.
After the user presses the "Order" button, I want to create an entry in backend using this service. There is a header and associated items that I need to pass.
oData Service from backend:
{
"d" : {
"__metadata" : {
"id" : "http://.../sap/opu/odata/sap/ZOrders/HeaderSet('3898')",
"uri" : "http://.../sap/opu/odata/sap/ZOrders/HeaderSet('3898')",
"type" : "ZOrder.Header"
},
"CompanyID" : "W",
"StockRoomID" : "A",
"SalesDocument" : "3898",
"ItemSet" : [
{
"__metadata" : {
"id" : "http://.../sap/opu/odata/sap/ZOrders/ItemSet(SalesDocument='3898',SalesDocumentItem='000010')",
"uri" : "http://.../sap/opu/odata/sap/ZOrders/ItemSet(SalesDocument='3898',SalesDocumentItem='000010')",
"type" : "ZOrders.Item"
},
"SalesDocument" : "3898",
"SalesDocumentItem" : "000010", //Line item number
"StockRoomID" : "A",
}
]
}
}
Controller.js
buttonClick: function(event) {
var sServiceURl = this.getOwnerComponent().getMetadata().getManifestEntry("sap.app").dataSources["ZOrders"].uri;
this.OdataModel = new sap.ui.model.odata.v2.ODataModel(sServiceURl);
var model = vc.getView().getModel();
var oEntry = {};
oEntry.CompanyID = model.getProperty("/CompanyID");
oEntry.StockRoomID = model.getProperty("/StockRoomID");
oEntry.SalesDocument = model.getProperty("/SalesDocument");
//Now want to pass items data to service so
//Creating an empty ItemSet array, pulling data from model.
//But my logic is wrong here for sure.
var itemData = [];
var itemsArray = v.getProperty("/ItemSet");
for (var i = 0; i < itemsArray.results.length; i++) {
itemData.push({
SalesDocument: itemsArray.results[i].SalesDocument,
SalesDocumentItem: itemsArray.results[i].SalesDocumentItem,
StockRoomID: itemsArray.results[i].StockRoomID,
});
}
oEntry.ItemSet = itemData;
this.OdataModel.create("/HeaderSet", oEntry, this._submitOrderSuccess.bind(this), this._submitOrderError.bind(this));
**Debugger - Header payload **
{
"CompanyID":"RSW0",
"StockRoomID":"A200",
"SalesDocument":"4053",
"Return":"X",
"Reason":"101",
"ItemSet":[
{
"SalesDocument":"4053",
"SalesDocumentItem":"000010",
"StockRoomID":"A200",
"ReturnItemFlag":"X",
"QtyToReturn":"1.000"
},
{
"SalesDocument":"4053",
"SalesDocumentItem":"000020",
"StockRoomID":"A200",
"ReturnItemFlag":"X",
"QtyToReturn":"1.000"
},
{
"SalesDocument":"4053",
"SalesDocumentItem":"000030",
"StockRoomID":"A200",
"ReturnItemFlag":"X",
"QtyToReturn":"1.000"
}
]
}
**Debugger - Response **
{
"d":{
"__metadata":{
"id":"https://.../sap/opu/odata/sap/ZORDER/HeaderSet('60000353')",
"uri":"https://.../sap/opu/odata/sap/ZORDER/HeaderSet('60000353')",
"type":"ZORDER.Header"
},
"CompanyID":"",
"StockRoomID":"",
"SalesDocument":"60000353",
"ReferenceDoc":"",
"AccountNumber":"",
"PoNumber":"",
"Message":"Return order 0060000353 has been created successfully",
"OrderTotal":"0.00",
"StockRoomName":"",
"Return":"",
"Reason":"",
"Auth":"",
"ItemSet":null,
"HeaderCSDSet":{
"__deferred":{
"uri":"https://.../sap/opu/odata/sap/ZORDER/HeaderSet('60000353')/HeaderCSDSet"
}
},
"AddressSet":{
"__deferred":{
"uri":"https://.../sap/opu/odata/sap/ZORDER/HeaderSet('60000353')/AddressSet"
}
},
"GeneralCommentsSet":{
"__deferred":{
"uri":"https://.../sap/opu/odata/sap/ZORDER/HeaderSet('60000353')/GeneralCommentsSet"
}
},
"CreditCardSet":{
"__deferred":"uri":"https://.../sap/opu/odata/sap/ZORDER/HeaderSet('60000353')/CreditCardSet"
}
}
}
}
This is a scenario of dependant Entity or Navigation property from Header to Item. Google "Deep Entity in SAPUI5 and oData for more understanding".
There is an error in your code where you have mentioned: "the logic is wrong".
Just add one line after the for loop:
oEntry.Items = ItemSet;
Let me know if this helps.

Google docs spreadsheet script error OAuthConfig when fetching data from Fitbit

I have got following script in Google docs spreadsheet which is fetching data from Fitbit. Script worked fine so far but recently on 6th July Google stopped using OAuthConfig so script is not working since:-(
I am not programmer, I am just advanced user. So I would like to kindly ask some programmer to help tune script below in order to make it work again.
// Key of ScriptProperty for Firtbit consumer key.
var CONSUMER_KEY_PROPERTY_NAME = "fitbitConsumerKey";
// Key of ScriptProperty for Fitbit consumer secret.
var CONSUMER_SECRET_PROPERTY_NAME = "fitbitConsumerSecret";
// Default loggable resources (from Fitbit API docs).
var LOGGABLES = ["activities/log/steps", "activities/log/distance",
"activities/log/activeScore", "activities/log/activityCalories",
"activities/log/calories", "foods/log/caloriesIn",
"activities/log/minutesSedentary",
"activities/log/minutesLightlyActive",
"activities/log/minutesFairlyActive",
"activities/log/minutesVeryActive", "sleep/timeInBed",
"sleep/minutesAsleep", "sleep/minutesAwake", "sleep/awakeningsCount",
"body/weight", "body/bmi", "body/fat",];
// function authorize() makes a call to the Fitbit API to fetch the user profile
function authorize() {
var oAuthConfig = UrlFetchApp.addOAuthService("fitbit");
oAuthConfig.setAccessTokenUrl("https://api.fitbit.com/oauth/access_token");
oAuthConfig.setRequestTokenUrl("https://api.fitbit.com/oauth/request_token");
oAuthConfig.setAuthorizationUrl("https://api.fitbit.com/oauth/authorize");
oAuthConfig.setConsumerKey(getConsumerKey());
oAuthConfig.setConsumerSecret(getConsumerSecret());
var options = {
"oAuthServiceName": "fitbit",
"oAuthUseToken": "always",
};
// get the profile to force authentication
Logger.log("Function authorize() is attempting a fetch...");
try {
var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/profile.json", options);
var o = Utilities.jsonParse(result.getContentText());
return o.user;
}
catch (exception) {
Logger.log(exception);
Browser.msgBox("Error attempting authorization");
return null;
}
}
// function setup accepts and stores the Consumer Key, Consumer Secret, firstDate, and list of Data Elements
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle("Setup Fitbit Download");
app.setStyleAttribute("padding", "10px");
var consumerKeyLabel = app.createLabel("Fitbit OAuth Consumer Key:*");
var consumerKey = app.createTextBox();
consumerKey.setName("consumerKey");
consumerKey.setWidth("100%");
consumerKey.setText(getConsumerKey());
var consumerSecretLabel = app.createLabel("Fitbit OAuth Consumer Secret:*");
var consumerSecret = app.createTextBox();
consumerSecret.setName("consumerSecret");
consumerSecret.setWidth("100%");
consumerSecret.setText(getConsumerSecret());
var firstDate = app.createTextBox().setId("firstDate").setName("firstDate");
firstDate.setName("firstDate");
firstDate.setWidth("100%");
firstDate.setText(getFirstDate());
// add listbox to select data elements
var loggables = app.createListBox(true).setId("loggables").setName(
"loggables");
loggables.setVisibleItemCount(4);
// add all possible elements (in array LOGGABLES)
var logIndex = 0;
for (var resource in LOGGABLES) {
loggables.addItem(LOGGABLES[resource]);
// check if this resource is in the getLoggables list
if (getLoggables().indexOf(LOGGABLES[resource]) > -1) {
// if so, pre-select it
loggables.setItemSelected(logIndex, true);
}
logIndex++;
}
// create the save handler and button
var saveHandler = app.createServerClickHandler("saveSetup");
var saveButton = app.createButton("Save Setup", saveHandler);
// put the controls in a grid
var listPanel = app.createGrid(6, 3);
listPanel.setWidget(1, 0, consumerKeyLabel);
listPanel.setWidget(1, 1, consumerKey);
listPanel.setWidget(2, 0, consumerSecretLabel);
listPanel.setWidget(2, 1, consumerSecret);
listPanel.setWidget(3, 0, app.createLabel(" * (obtain these at dev.fitbit.com)"));
listPanel.setWidget(4, 0, app.createLabel("Start Date for download (yyyy-mm-dd)"));
listPanel.setWidget(4, 1, firstDate);
listPanel.setWidget(5, 0, app.createLabel("Data Elements to download:"));
listPanel.setWidget(5, 1, loggables);
// Ensure that all controls in the grid are handled
saveHandler.addCallbackElement(listPanel);
// Build a FlowPanel, adding the grid and the save button
var dialogPanel = app.createFlowPanel();
dialogPanel.add(listPanel);
dialogPanel.add(saveButton);
app.add(dialogPanel);
doc.show(app);
}
// function sync() is called to download all desired data from Fitbit API to the spreadsheet
function sync() {
// if the user has never performed setup, do it now
if (!isConfigured()) {
setup();
return;
}
var user = authorize();
// Spatny kod, oprava nize - var doc = SpreadsheetApp.getActiveSpreadsheet();
var doc = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pavel');
doc.setFrozenRows(1);
var options = {
"oAuthServiceName": "fitbit",
"oAuthUseToken": "always",
"method": "GET"
};
// prepare and format today's date, and a list of desired data elements
var dateString = formatToday();
var activities = getLoggables();
// for each data element, fetch a list beginning from the firstDate, ending with today
for (var activity in activities) {
var currentActivity = activities[activity];
try {
var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/"
+ currentActivity + "/date/" + getFirstDate() + "/"
+ dateString + ".json", options);
} catch (exception) {
Logger.log(exception);
Browser.msgBox("Error downloading " + currentActivity);
}
var o = Utilities.jsonParse(result.getContentText());
// set title
var titleCell = doc.getRange("a1");
titleCell.setValue("date");
var cell = doc.getRange('a2');
// fill the spreadsheet with the data
var index = 0;
for (var i in o) {
// set title for this column
var title = i.substring(i.lastIndexOf('-') + 1);
titleCell.offset(0, 1 + activity * 1.0).setValue(title);
var row = o[i];
for (var j in row) {
var val = row[j];
cell.offset(index, 0).setValue(val["dateTime"]);
// set the date index
cell.offset(index, 1 + activity * 1.0).setValue(val["value"]);
// set the value index index
index++;
}
}
}
}
function isConfigured() {
return getConsumerKey() != "" && getConsumerSecret() != "";
}
function setConsumerKey(key) {
ScriptProperties.setProperty(CONSUMER_KEY_PROPERTY_NAME, key);
}
function getConsumerKey() {
var key = ScriptProperties.getProperty(CONSUMER_KEY_PROPERTY_NAME);
if (key == null) {
key = "";
}
return key;
}
function setLoggables(loggable) {
ScriptProperties.setProperty("loggables", loggable);
}
function getLoggables() {
var loggable = ScriptProperties.getProperty("loggables");
if (loggable == null) {
loggable = LOGGABLES;
} else {
loggable = loggable.split(',');
}
return loggable;
}
function setFirstDate(firstDate) {
ScriptProperties.setProperty("firstDate", firstDate);
}
function getFirstDate() {
var firstDate = ScriptProperties.getProperty("firstDate");
if (firstDate == null) {
firstDate = "2012-01-01";
}
return firstDate;
}
function formatToday() {
var todayDate = new Date;
return todayDate.getFullYear()
+ '-'
+ ("00" + (todayDate.getMonth() + 1)).slice(-2)
+ '-'
+ ("00" + todayDate.getDate()).slice(-2);
}
function setConsumerSecret(secret) {
ScriptProperties.setProperty(CONSUMER_SECRET_PROPERTY_NAME, secret);
}
function getConsumerSecret() {
var secret = ScriptProperties.getProperty(CONSUMER_SECRET_PROPERTY_NAME);
if (secret == null) {
secret = "";
}
return secret;
}
// function saveSetup saves the setup params from the UI
function saveSetup(e) {
setConsumerKey(e.parameter.consumerKey);
setConsumerSecret(e.parameter.consumerSecret);
setLoggables(e.parameter.loggables);
setFirstDate(e.parameter.firstDate);
var app = UiApp.getActiveApplication();
app.close();
return app;
}
// function onOpen is called when the spreadsheet is opened; adds the Fitbit menu
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{
name: "Sync",
functionName: "sync"
}, {
name: "Setup",
functionName: "setup"
}, {
name: "Authorize",
functionName: "authorize"
}];
ss.addMenu("Fitbit", menuEntries);
}
// function onInstall is called when the script is installed (obsolete?)
function onInstall() {
onOpen();
}
Problem solved with updated code at https://github.com/loghound/Fitbit-for-Google-App-Script

Blackberry 10 Cascades - search-ahead drop-down + tag field

My question is related to Filipe Figueiredo's query (see: Blackberry 10 Cascades - Images inside Text Area)
My Cascades BB10 App requires a search-ahead drop-down with the ability to have multiple items selected and displayed as Tag Fields. Look & feel and behavior same as BB10 email composer's "To" address field - but with different data (e.g. country names).
Questions:
Is there a way to do this using Cascades components / controls?
(FlowListLayout does not meet exact requirements)
Can we achieve this using QML + javascript?
Or is there a way using C++ and QML for achieving this?
Is there a Component market Place for procuring custom controls for Cascades?
My development is stalled. Please help.
It should be possible. This is a prototype. It doesn't work well, but it's an idea. This is how it looks:
Code (yeah, it's bad. but it should work out of the box):
import bb.cascades 1.2
Page {
Container {
ListView {
id: tagList
dataModel: tagModel
layout: FlowListLayout {
headerMode: ListHeaderMode.None
}
preferredHeight: 200
function itemType(data, indexPath) {
return (data.add == 1 ? 'add' : '');
}
function mload(text) {
myList.load(text);
}
function showDropDown() {
myList.visible = true;
}
listItemComponents: [
ListItemComponent {
type: "add"
Container {
id: myAdd
TextField {
id: searchBox
preferredWidth: 300
onTextChanging: {
myAdd.ListItem.view.mload(searchBox.text);
}
onFocusedChanged: {
if (focused)
myAdd.ListItem.view.showDropDown();
}
}
}
},
ListItemComponent {
Container {
background: Color.create("#660000FF")
leftPadding: 10
rightPadding: 10
topPadding: 10
bottomPadding: 10
leftMargin: 10
bottomMargin: 10
Label {
id: country
textStyle.fontSize: FontSize.Medium
text: ListItemData.country
}
}
}
]
onTriggered: {
//todo: make it possible to remove a tag
console.log("item touched.. yay!")
}
attachedObjects: [
ArrayDataModel {
id: tagModel
}
]
}
ListView {
id: myList
visible: false
dataModel: mdataModel
preferredHeight: 400
attachedObjects: [
ArrayDataModel {
id: mdataModel
}
]
onTriggered: {
var selected = dataModel.data(indexPath);
var tmp = new Object();
tmp.country = selected;
tagModel.insert(tagModel.size() - 1, tmp);
console.log("removing: " + (tagModel.size() - 1 ) + " at size " + tagModel.size())
visible = false;
}
function load(text) {
var cities = [ "Slovenia", "Italy", "Slovakia", "Croatia", "Sweden", "Norway", "Poland", "Finland", "Spain",
"Indonesia", "Ireland" ]
var tmp = [];
for (var i = 0; i < cities.length; i ++)
if (cities[i].toLowerCase().indexOf(text.toLowerCase()) >= 0)
tmp.push(cities[i]);
mdataModel.clear();
mdataModel.insert(0, tmp);
}
function insertEdit() {
var edit = new Object();
edit["add"] = "1";
tagModel.insert(tagModel.size(), edit);
}
}
}
onCreationCompleted: {
myList.load("");
myList.insertEdit(); // insert item with TextField
}
}

407 Proxy Error Encountered with Fusion Tables

When I try to use the docid in place of the table id I get a 407 proxy error. My understanding is that you don't need to authenticate for selecting records, only for inserts, updates, and deletes. When I use the table id, the sql query hangs. I noticed these errors in the Firebug console window.
I am able to receive data from both tables (levels_a.txt & levels_b.txt) when the tables aren't merged. The same isn't true when they are merged. Please see below for my code.
google.load("visualization", "1", { packages: ["corechart", "annotatedtimeline"] });
var map, layer;
var tableID = 3013978;
//var tableID = "1RWnj3geWmOXHcedu8RUeyb1v4ZjZz3YWNpK0MDs";
var location_column = 'geometry';
var name, PID;
var chart;
var jqXHR;
var formatter_long;
var dt;
var rows;
var plot;
var scatter_chart;
var g;
function initialize() {
var latlng = new google.maps.LatLng(53.760861, -98.813876);
var myOptions = {
center: latlng,
zoom: 5,
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL
},
mapTypeControl: true,
mapTypeControlOptions: {
mapTypeIds: [
google.maps.MapTypeId.ROADMAP,
google.maps.MapTypeId.SATELLITE,
google.maps.MapTypeId.HYBRID,
google.maps.MapTypeId.TERRAIN
],
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
},
overviewMapControl: true,
overviewMapControlOptions: {
opened: true
}
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
layer = new google.maps.FusionTablesLayer({
query: {
select: location_column,
from: tableID
}
});
layer.setMap(map);
google.maps.event.addListener(layer, 'click', function (e) {
name = e.row['name'].value;
PID = e.row['WELL_PID'].value;
drawChart(PID, name);
});
}
function drawChart(PID, name) {
/*
var queryURL = "http://www.google.com/fusiontables/api/query?sql=";
var queryTail = '&jsonCallback=?';
var whereClause = "WHERE 'WELL_PID'=" + PID; // table id 3004502
var query = "SELECT 'Date','Level' FROM 3004502 " + whereClause;
var queryText = encodeURIComponent(query);
*/
//--------------------------------------------------------------------------------------------//
var queryUrlHead = 'http://www.google.com/fusiontables/api/query?sql=';
var queryUrlTail = '&jsonCallback=?';
var whereClause = "WHERE 'WELL_PID'=" + PID; // table id 3004502
var query = "SELECT 'Date','Level' FROM 1RrJI_dWPjrmJ7A6xD_GcZ3nxIso9ZTvOPWp0suI " + whereClause;
var queryurl = encodeURI(queryUrlHead + query + queryUrlTail);
var jqxhr = $.get(queryurl, dataHandler, "jsonp");
//console.log(jqxhr);
/*
var rows;
var items = [];
var arr = [];
var str;
$.ajax({
type: "GET",
url: queryURL + queryText + queryTail,
cache: false,
dataType: 'jsonp',
jsonpCallback: 'jsonpCallback',
success: function (data) {
rows = data.table.rows;
for (i = 0; i < rows.length; i++) {
var temp = rows[i];
var this_date;
items.push([parseDate(temp[0]), temp[1]]);
}
processData(items);
},
error: function () { alert("Please wait until chart loads before clicking on another well location."); }
});
*/
}
function dataHandler(d) {
var items = [];
var rows = d.table.rows;
for (i = 0; i < rows.length; i++) {
var temp = rows[i];
var this_date;
items.push([parseDate(temp[0]), temp[1]]);
}
processData(items);
}
function processData(res) {
var options = {
strokeWidth: 0.0,
displayAnnotations: true,
labelsKMB: false,
rollPeriod: 14,
showRangeSelector: true,
connectSeparatedPoints: false,
drawPoints: true,
stepPlot: false,
pointSize: 1,
digitsAfterDecimal: 3
};
var dat = new google.visualization.DataTable();
dat.addColumn('date', 'Date');
dat.addColumn('number', 'Water Level');
console.log(res.toString());
if (res.toString() === "") {
alert("Sorry, there is no data available for this well. Please check back at a later time.");
$("#dg_div").empty();
} else {
dat.addRows(res);
if (g) {
g.destroy();
}
g = new Dygraph(document.getElementById("dg_div"), dat, options);
}
}
I would like to perform the following joins:
geography.kml
name | geometry | description
well_name_and_PID.csv
WELL_PID | Name_Short
levels_a.txt
WELL_PID | Date | Level
levels_b.txt
WELL_PID | Date | Level
Joins:
[geography.kml].name -> [well_name_and_PID.csv].Name_Short
[well_name_and_PID.csv].WELL_PID -> [levels_a.txt].WELL_PID
[well_name_and_PID.csv].WELL_PID -> [levels_b.txt].WELL_PID
The rationale behind having two level files is that this file would othewise exceed the 100 meg table cap. These two files contain similar information.
As usual, any help on this is greatly appreciated.
Thanks in advance,
Michael

Resources