I have a query returning the top ten most visited pages over a specific date range and it works the first time the page loads, but when the query is rerun I get the error:
You called the draw() method with the wrong type of data rather than a DataTable or DataView
Here is the code:
function renderDataTable(viewID){
var dateRange = getDateRange(),dataQuery;
dataQuery = query({
ids: 'ga:' + viewID,
metrics: 'ga:pageviews,ga:avgTimeOnPage,ga:entrances,ga:bounceRate,ga:exitRate',
dimensions: 'ga:pageTitle',
sort:'-ga:pageviews',
'max-results':10,
'start-date': moment(dateRange.start).format('YYYY-MM-DD'),
'end-date':moment(dateRange.end).format('YYYY-MM-DD')
}).then(function(results){
var colltypes =['string','string','avgtime','string','percent','percent'],x=0,
i=0,
row=[],
rows=[],
data = new google.visualization.DataTable();
if(results.totalResults > 0){
data.addColumn('string', stStats.pagetitle);
data.addColumn('string', stStats.pagevisits);
data.addColumn('string', stStats.duration);
data.addColumn('string', stStats.entrances);
data.addColumn('string', stStats.bouncerate);
data.addColumn('string', stStats.exitpercent);
for(x=0;x<results.rows.length;++x){
//rows
row =[];
for(i=0;i<results.rows[x].length;++i){
//format columns
row.push( formatTotals(results.rows[x][i], colltypes[i]));
}
rows.push(row);
}
data.addRows(rows);
var table = new google.visualization.Table(document.getElementById('table-1-container'));
table.draw(data, {showRowNumber: true, width: '100%', height: '100%'});
}
});
}
the first time round the call to new google.visualization.DataTable() produces an object that in the console looks like:
gvjs_P {Vm: null, OA: "0.6", ng: Array(0), og: Array(0), Hr: null, …}
when I call the function again, with either exactly the same query params or different I get the error and the result from the call to the DataTable is different.
gvjs_R {Pm: null, IA: "0.6", Mf: Array(0), Nf: Array(0), vr: null, …}
this is before I have added rows or anything.. whats even more annoying I can't replicate the problem in a simple fiddle.. which means there has to be a problem with my code somewhere but I can't seem to find it.. any help would be appreciated.
ps the query function was taken from the embed api example, and it appears only to happen when there are two charts on the same page.. One is created using the embed api the other with the visualization api..
Related
I'm using SpreadJS v12 as a reporting tool. User will enter the page get the wanted data, create charts and save it for later use.
When user saves the report I get Json data (GC.Spread.Sheets.Workbook.toJSon) and save this Json to database and whenever someone tries to reach the same report, I get the Json from database and give it to the page (GC.Spread.Sheets.Workbook.fromJSon). Everything works fine except if there is a chart on page the data source for chart series (xValues and yValues) change. When I check Json format it looks like this: Sheet2!$B$2:$B$25 but in chart it's: Sheet2!$A$1:$A$24 . Am I doing something wrong?
By the way my serialize options: { ignoreFormula: false, ignoreStyle: false, rowHeadersAsFrozenColumns: true, columnHeadersAsFrozenRows: true, doNotRecalculateAfterLoad: false }
this.state.spread = new GC.Spread.Sheets.Workbook(document.getElementById("spreadSheetContent"), { sheetCount: 1 });
This is my save method:
var pageJson = this.state.spread.toJSON(this.serializationOption);
let self = this;
let model = {
Id: "",
Name: reportName,
Query: query,
PageJson: JSON.stringify(pageJson)
}
this.post( { model }, "Query/SaveReportTemplate")
.done(function(reply){
self.createSpreadSheet(reply);
}).fail(function(reply){
self.PopUp(reply, 4 );
});
And this is my load method:
var jsonOptions = {
ignoreFormula: false,
ignoreStyle: false,
frozenColumnsAsRowHeaders: true,
frozenRowsAsColumnHeaders: true,
doNotRecalculateAfterLoad: false
}
this.state.spread.fromJSON(JSON.parse(template.PageJson),jsonOptions);
this.state.spread.repaint();
Well after a long day, I think I've found what's causing the problem and started working around that.
Let's say we have two sheets. Sheet1's index is 0 and Sheet2's index is 1.
Because of the json serialization options like frozenColumnsAsRowHeaders and frozenRowsAsColumnHeaders until Sheet2 is painted row numbers and column number are different in the json.
If there is a formula or a chart in Sheet1 that's referencing Sheet2, their references will point to a different cell from what you set first. So always referencing the sheets that will be painted before is the way to solve this problem.
I am having an issue with a growing list. Previously I had a normal list, but as it is limited to displaying 100 items, I need to now change this to a growing list, which works fine now and I can get over 100 items loaded when I've put the growing="true" growingThreshold="50" growingScrollToLoad="false" properties on the list.
But now I have an issue with one of the number inputs in the custom list, when entering a number it is not staying set (it has a liveChange event that updates a text component).
I've set a breakpoint in the controller to test and it seems to bug out when I am trying to set the data changes (red arrow on attached image).
Can anyone see the issue with the logic? If any additional code snippets are required I could provide them.
onReceivedQuantityChange: function (oEvent) {
// get model and data
var oModel = this.getOrderModel();
var oData = oModel.getData();
// get item from path
var oItem = this._getOrderItemByPath(oEvent.getSource().getBindingContext(this.MODEL_ORDERS).getPath());
// set received value
oItem._ReceivedValue = oEvent.getParameters().newValue * (oItem.ValuationPrice / oItem.Quantity);
// apply data changes
oModel.setData(oData);
},
Controller code image
onReceivedQuantityChange: function (oEvent) {
var oModel = this.getOrderModel()
var sItemPath = oEvent.getSource().getBindingContext(this.MODEL_ORDERS).getPath()
var iValuationPrice = oModel.getProperty(sItemPath + '/ValuationPrice')
var iQuantity = oModel.getProperty(sItemPath + '/Quantity')
var iNewValue = oEvent.getParameters().newValue
var iReceivedValue = iNewValue * (iValuationPrice / iQuantity)
oModel.setProperty(sItemPath + '/_ReceivedValue', iReceivedValue)
}
If you use setProperty() on the Model you're only chaning the specific Property in DataModel and Sapui5 is able to proceed bindingchanges on this Property only (and not the whole model).
If you get the data out of the model by getData() you are only getting a reference to this Object. If you change something on this Object, you don't have to set it back by setData() (it is already there because you used the reference of this Object).
But Sapui5 need to know that there was a specific change in datamodel and this is done by using setProperty()
I am trying to insert a record in one entity that has a List field that references another entity. The relation is supposed to be one-to-many.
var order = new DB.Order({
order_code: '444',
customer:DB.me,
items:["/db/Item/0ecf15c9-ae4f-441a-ad14-d89d338d6303", "/db/Item/2caea632-5a8c-4101-a736-0bb2a4623fa3"],
});
order.insert();
Apparently inserting the referenced value in this format ["/db/Item/xxxxx", "/db/Item/xxxxx"] will not work from javascript and the inserted value will be [null, null], even though this format will work in the dashboard.
Any help in this regard will be appreciate.
the SDK needs an instance of the object to correctly save the reference:
var firstItem = new DB.Item();
var secondItem = new DB.Item();
var order = new DB.Order({
order_code: '444',
customer:DB.me,
items:[firstItem, secondItem],
});
order.insert();
If you don't have the objects, you can get them by calling DB.getReference
var order = new DB.Order({
order_code: '444',
customer:DB.me,
items:[DB.getReference("/db/Item/0ecf15c9-ae4f-441a-ad14-d89d338d6303"), DB.getReference("/db/Item/2caea632-5a8c-4101-a736-0bb2a4623fa3")],
});
order.insert();
The IBM Watson iOS SDK using the Alchemy News service on Bluemix returns a string result which requires parsing to pull out the fields like url and cleaned title. ref: https://github.com/watson-developer-cloud/swift-sdk
I pull the string into an array and parse it in swift3 using some string methods but this is pretty ordinary and can produce unpredictable results
Is there a more elegant approach where I can access specific fields, like the url and cleaned title which I am passing to a UITableViewCell to select and segue to the url link.
sample code:
let alchemyDataNews = AlchemyDataNews(apiKey: apiKey)
let failure = { (error: Error) in print(error) }
let start = "now-14d" // 7 day ago
let end = "now" // today
let query = ["count": "15",
"dedup": "true",
"q.enriched.url.title": "[IBM]",
"return": "enriched.url.url,enriched.url.title" "enriched.url.title,enriched.url.entities.entity.text,enriched.url.entities.entity.type"]
Also I have noticed the search string [IBM] has a prefix of 0, i.e. 0[IBM] and have also seen an "A". What do these prefixes mean and where are they documented
Here is one way you can access the fields from a returned payload.
alchemyDataNews.getNews(from: "now-4d", to: "now", query: queryDict, failure: failWithError) { news in
for doc in (news.result?.docs)! {
var cleanedTitle = doc.source?.enriched?.url?.cleanedTitle
var author = doc.source?.enriched?.url?.author
var title = doc.source?.enriched?.url?.title
}}
Also, here is a nice API reference link for alchemy data which contains all of the request parameters and filters.
https://www.ibm.com/watson/developercloud/alchemydata-news/api/v1/
Can a Date.now type function be used in either map or reduce functions? Can it be used anywhere at all?
More specifically, the view must not cache the Date.now value.
Here is what I tested that only worked for the first run after a change to any view function:
function (doc){
var n = new Date();
if(doc.TimeStamp > n.getTime() - 30000){
emit(doc._id, doc);
}
}
The view rows will be refreshed only when the particular doc gets updated. But you can request the view for that result: emit the doc.TimeStamp as key and request the view with ?startkey=timestamp where timestamp is the value of now.getTime() - 30000.
Yes. var now = new Date() should work.
The condition must result in false. You can test it with the view:
function (doc) {
var now = new Date()
var timestamp = now.getTime()
emit(timestamp,null)
}
It will respond something like
{
"total_rows":1,
"offset":0,
"rows" :[{
"id":"ecd99521eeda9a79320dd8a6954ecc2c",
"key":1429904419591, // timestamp as key
"value":null
}]
}
Make sure that doc.TimeStamp is a number (maybe you have to execute parseInt(doc.TimeStamp)) and greater then timestamp - 30000
Two words about your line of code emit(doc._id, doc);:
To emit doc._id as key means maybe you doesn't need the view. Simply request the doc by GET /databasename/:id. Also to include doc._id in multipart keys or the value of the view row is mostly not necessary because its included in every row automatically as additional property. One valid reason would be when you want to sort the view over the doc ids.
To emit the doc as value is not recommended for performance reasons of the view. Simply add ?include_docs=true when you request the view and every row will have an additional property doc with whole doc in it.