I am attempting to use a google spreadsheet as a temporary database. I have followed the instructions at the folowing tutorial and everything is working fine
http://www.alatechsource.org/blog/2012/05/using-the-google-spreadsheets-data-api-to-build-a-recommended-reading-list-code-words.h
The jquery that gets the data I have copied below for ref
I wondered if it would be possible (using the same or similar code), assuming there are multiple sheets within the spreadsheet to query just one at a time. So for example you could run the below code but only for say sheet 4.
I have tried adding sheet ref # from the web URL (i.e #gid=1) at the end of the numeric code so
"https://spreadsheets.google.com/feeds/list/0Ak0qDiMLT3XddHlNempadUs1djdkQ0tFLWF6ci1rUUE/od6/public/values?alt=json-in-script&callback=?"
becomes
"https://spreadsheets.google.com/feeds/list/0Ak0qDiMLT3XddHlNempadUs1djdkQ0tFLWF6ci1rUUE#gid=1/od6/public/values?alt=json-in-script&callback=?"
but this does not work, the code only seems to loop through the first sheet
Can anyone advise on this?
Any help is much appreciated
<script type="text/javascript">
$(document).ready(function() {
//source file is https://docs.google.com/spreadsheet/ccc? key=0Ak0qDiMLT3XddHlNempadUs1djdkQ0tFLWF6ci1rUUE
$(function listBooks() {
$.getJSON( "https://spreadsheets.google.com/feeds/list/0Ak0qDiMLT3XddHlNempadUs1djdkQ0tFLWF6ci1rUUE/od6/public/values?alt=json-in-script&callback=?",
function (data) {
$('div#book-list').append('<ul class="items"></ul>');
$.each(data.feed.entry, function(i,entry) {
var item = '<span style="display:none">' + entry.id.$t + '</span>';
item += '<img src="http://covers.openlibrary.org/b/isbn/' + entry.gsx$isbn.$t + '-S.jpg"/>';
item += '<span class="meta">' + entry.title.$t + '';
item += '<br/>Author: ' + entry.gsx$author.$t;
if (entry.gsx$notes.$t) {
item += '<br/>Description: ' + entry.gsx$notes.$t;
}
$('.items').append('<li>' + item + '</span></li>');
});
});
});
});
</script>
Ok, I have a solution for anyone who is interested, although it is not as sensible as I would have hoped
Thanks to the below blogpost
http://damolab.blogspot.co.uk/2011/03/od6-and-finding-other-worksheet-ids.html
It seems that the id for specific sheets is the /od6/ part of the URL and od6 is the default name given to the first, default, sheet
"https://spreadsheets.google.com/feeds/list/0Ak0qDiMLT3XddHlNempadUs1djdkQ0tFLWF6ci1rUUE/od6/public/values?alt=json-in-script&callback=?"
In the above blog post there is an example of how to find out the IDs of specific sheets if you need. There doesn't seem to be a clean logic to it but changing it will spit out the data from specific sheets so it works.
I realize this is an old post, but I have been fighting this for a while. I made my own library to take care of this and I hope this saves someone many hours of research and playing with the google api. The general format is almost verbatim from the google documentation and I removed error checking to stay concise. What I could not find in the google documentation was how to query a tab that isn't the first one. I think this is what we are looking for here.
Based on what you already have, this should answer it.
table_name_here/gviz/tq?sheet=tab_name_here
As an example for all those that come after you:
https://docs.google.com/spreadsheets/d/17mbdvl1jVpqj42E3BSX34q9XUA2PbYubYKpVeypbHLA/gviz/tq?sheet=Sheet1
This could be used as the table_string in the code below.
'SELECT *'
This could be used as the query_string in the code below.
Within context:
function gimmeATable(){
var query = new google.visualization.Query('table_string');
query.setQuery('query_string');
query.send(handleQueryResponse);
}
function handleQueryResponse(response){
var data = response.getDataTable;
drawTable(data);
}
function drawTable(data){
var table = new google.visualization.Table(document.getElementById('div1'));
table.draw(data, {showRowNumber: true});
}
And don't forget to include the google api as well as package type. For this you only need a table.
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
google.load("visualization", '1', {packages:['table']});
Related
I am using in visualforce page of Salesforce.com. For demo purposes, I have used the following code snippet from the example docs shown in
http://docs.releasenotes.salesforce.com/en-us/spring14/release-notes/rn_vf_remote_objects.htm
In my code snippet i have a 'Where' clause in which i am trying to filter using 3 fields. My requirement is that the records must match the criteria A or criteria B or criteria C.
Code Example
<apex:page >
<!-- Remote Objects definition to set accessible sObjects and fields -->
<apex:remoteObjects >
<apex:remoteObjectModel name="Group_Donor__c" jsShorthand="Groupdonor"
fields="Name,Id">
<apex:remoteObjectField name="State__c" jsShorthand="State"/>
<apex:remoteObjectField name="Org_Phone__c" jsShorthand="Phone"/>
<apex:remoteObjectField name="Billing_Type__c" jsShorthand="billingtype"/>
</apex:remoteObjectModel>
</apex:remoteObjects>
<!-- JavaScript to make Remote Objects calls -->
<script>
var fetchWarehouses = function(){
// Create a new Remote Object
var wh = new SObjectModel.Groupdonor();
// Use the Remote Object to query for 10 warehouse records
wh.retrieve({
where: {
or: {
Name : {like:"%Helloworld%"}, // Error
State: {like:"%chennai%"},
//Phone: {like:"%098765432344%"},
billingtype: {like:"%Credit Card%"}
}
},
limit: 10 ,
}, function(err, records, event){
if(err) {
alert(err.message);
}
else {
var ul = document.getElementById("warehousesList");
records.forEach(function(record) {
// Build the text for a warehouse line item
var whText = record.get("Name");
whText += " -- ";
whText += record.get("Phone");
whText += " -- ";
whText += record.get("billingtype");
// Add the line item to the warehouses list
var li = document.createElement("li");
li.appendChild(document.createTextNode(whText));
ul.appendChild(li);
});
}
});
};
</script>
<h1>Retrieve Group Donors via Remote Objects</h1>
<p>Warehouses:</p>
<ul id="warehousesList">
</ul>
<button onclick="fetchWarehouses()">Retrieve Group Donors</button>
</apex:page>
When i execute this code i get the following error.
Error Message :
Invalid criteria specified for retreival. ValidationError [code=11, message=Data does not match any schemas from "oneOf" path=/where, schemaKey=null]
This issue occurs only during the following conditions.
When i use Standard field like Name in the OR condition. ( Even 2 or 1 filter)
When i use more than 3 Custom fields in the OR condition ( More than 2 Query filter)
But when i use just any 2 custom fields mentioned in the RemoteObjectModel as filters, i get the expected results.
Kindly let me know what am i missing here. If i have use more than 2 filters in or condition, how do i achieve it ? is the usage of 'OR' proper in the remote-objects?. And has anyone come across this issue. if so kindly provide me some pointers.
Thanks in advance.
I've been doing some looking and there's some bad news and some good news.
First, it's a (obscure)known limitation that you can't have more than 2 predicates for AND and OR queries - Docs here
However, you seem to have discovered another bug in that an Standard Field (Name, Id) seems to not work when used with a custom one. My workaround was to redefine ALL fields, even standard ones like this:
<apex:remoteObjectModel name="Group_Donor__c" jsShorthand="GroupDonor">
<apex:remoteObjectField name="Name" jsShorthand="NameJS"/>
<apex:remoteObjectField name="State__c" jsShorthand="State"/>
<apex:remoteObjectField name="Org_Phone__c" jsShorthand="Phone"/>
<!--.... etc-->
At least you'll be able to query standard fields this way.
As an ultimate work around, you'll probably have to retrieve two lists of records and use JavaScript to create your ultimate OR list.
Good luck!
I'm using parsleyjs to validate my forms client-side. I have a scenario where, on click of a checkbox, some more form fields are exposed and need validating. If the checkbox is then unclicked the form fields are hidden and validation needs removing.
Is there functionality to achieve this in parsley? I've looked through the docs but can only find details of how to validate through attributes in the html. I'm looking for a method I can call in code to add and remove fields to be validated.
I ran into this exact situation a couple of weeks ago. You do need an extra bit of js to accomplish this. I dug around and found one bit of script that came close but needed some tweaking to suit my needs: it depended on predefined field definitions. No bueno. I wanted it to duplicate fields regardless of their names/ids/whatever. Then, of course, increment each new field name. Also without cloning whatever values had been entered by the user.
Since the fields being cloned already have the necessary parsley validation, that just went right along with them.
Here's the cloning code I came up with. I'm sure it can use improvement. And here's a fiddle with a working example.
this is my first contribution after years of lurking. be gentle. ;)
$('#btnDel').prop('disabled', true);
$('#btnAdd').prop('disabled', false);
$('#btnAdd').click(function() {
var num = $('.clonedInput').length;
var newNum = new Number(num + 1);
var newElem = $('#input1').clone().val('').attr('id', 'input' + newNum);
newElem.find(':input').attr('id', function () {
return this.id + '_' + newNum
});
newElem.find(':input').attr('name', function () {
return this.name + '_' + newNum
});
newElem.find(':input').val('');
$('#input' + num).after(newElem);
$('#btnDel').prop('disabled', false);
if (newNum == 5){
$('#btnAdd').prop('disabled', true);
}
});
$('#btnDel').click(function() {
var num = $('.clonedInput').length;
$('#input' + num).remove();
$('#btnAdd').prop('disabled', false);
if (num-1 == 1){
$('#btnDel').prop('disabled', true);
}
});
$('#btnDel').prop('disabled', true);
});
Parsley is great for most validation scenarios but in the past I've struggled to get it to do what I need - the lack of ability to programmatically interact with the validation lifecycle makes it less useful for more complex validations.
I wrote a library called Okjs that works in a very similar fashion to Parsley but with the added benefit that when you need to do something like add a new validator to a field based on user interaction there's a code API to allow you to do so:
https://github.com/jamesfiltness/Okjs
To add fields on click of a checkbox in Ok would go like so:
$('.my__checkbox').focus(function() {
Ok.Form.addField('checkbox1', ['required']);
Ok.Form.addField('checkbox2', ['required']);
})
NOTE: the following code and demo are extracted from a larger Meteor + Angular project.
I have the following functions to select and delete objects:
DEMO: http://plnkr.co/edit/Qi8nIPEd2aeXOzmVR6By?p=preview
$scope.selectParty = function(party) {
$scope.party = party;
$scope.type = party.type;
$scope.date = party.date;
}
$scope.deletParty = function(party) {
$scope.parties.remove(party);
}
$scope.selectOrganizer = function(organizer) {
$scope.organizer = organizer;
$scope.name = organizer.name;
$scope.title = organizer.title;
}
$scope.deletOrganizer = function(organizer) {
$scope.party.organizers.remove(organizer);
}
The Select action works on both Parties and Organizers as you can see in the demo, displaying the data in the table underneath.
The Delete action doesn't work. Although, let me point out that in my app, the one I have on my machine and currently working on in Meteor, the Delete action works splendidly on Parties, meaning the syntax "$scope.parties.remove(party)" works. But it doesn't work on the plnkr demo for some reason :(
My question is really about the Organizers Delete action, where I'm targeting an object (organizer) inside an array inside the selected object (party)… that one doesn't work. I'm wondering why, and what is the right syntax.
NOTE 2: I'm aware of Angular's splice and index but I can't use them here as I'm not simply working with Angular arrays but with database data in Meteor.
Thanks!
The organizer is a part of the party object and not a collection on it's own. So what you would need to do is remove the party from the object and then save the party object.
Note2 is incorrect. Unless you wrote your question and plunker wrong.
This isn't so much a question abut AngularJS as it is about the Wikimedia and Wikidata query API's.
Although I am trying to display the content of a Wikipedia article in AngularJS after doing a certain query that isn't the problem. I already know how to display it... the problem is the search for an article or articles.
I'm trying to query Wikipedia by historical event date as well as by geo-location.
Let's pick a random event, any event. Let's say "1986 Mozambican Tupolev Tu-134 crash". Link: http://en.wikipedia.org/wiki/1986_Mozambican_Tupolev_Tu-134_crash
From the article, I can see the exact date: 19 October 1986
as well as the geo-location of the event: -25.911389, 31.957222
I'm trying to build a search in AngularJS that can use either a date-range and/or geolocation coordinates to find an event.
I am aware that mediawiki has a geolocation API now, and I am able to find the above event by either keyword or coordinates. The result also turns up any other articles that exist within a certain radius around it using this:
http://en.wikipedia.org/w/api.php?action=query&list=geosearch&gsradius=10000&gscoord=-25.911389|31.957222&prop=extracts|info&exintro&titles=1986_Mozambican_Tupolev_Tu-134_crash&format=json&explaintext&redirects&inprop=url&indexpageids&format=json&callback=JSON_CALLBACK
However, there is no way to do a search with mediawiki by a point in time or the date of the event.
Wikidata on the other hand has two methods of searching data... it has a date range as well as geolocation.
However, when a query is run, I have no idea what is being returned.
For example, when I use this query string:
https://wdq.wmflabs.org/api?q=AROUND[625,-25.911389,31.957222,5]%20AND%20BETWEEN[585,1985,1987]
it returns this:
{"status":{"error":"OK","items":1,"querytime":"544ms","parsed_query":"(AROUND[625,-25.9114,31.9572,5]
AND
BETWEEN[585,+00000001985-00-00T00:00:00Z,+00000001987-00-00T00:00:00Z])"},"items":[950273]}
Using wikidata's query tool:
http://tools.wmflabs.org/autolist/autolist1.html?q=AROUND[625,-25.911389,31.957222,5]%20AND%20BETWEEN[585,1985,1987]
I can see that 950273 represents the article in some way. I'm just not sure how to use that to direct me to the actual article in wikipedia.
I don't know what "items": [950273]" represents, or how to use it to get me to the wikipedia article and display the contents of that article in AngularJS.
Is there a way to do both a query by date of the historical event as well as by geolocation. Either by using mediawiki or wikidata or a combination of the two?
EDIT:
This is the solution to my question above. It seems like a bit of a hack... but it works. Good enough for now. Here is my controller.
.controller('WikiQueryCtrl', ['$scope', '$http', function($scope, $http) {
$http({
//these geo coordinates and the date ranges will eventually be dynamic.
url: 'https://wdq.wmflabs.org/api?q=AROUND[625,-25.911389,31.957222,5]%20AND%20BETWEEN[585,1985,1987]&callback=JSON_CALLBACK',
method: 'jsonp'
})
.success(function(response) {
var items = response.items;
$scope.jason = items;
var wikiDataString = 'http://www.wikidata.org/w/api.php?action=wbgetentities&format=json&ids=Q' + items + '&props=sitelinks%7Csitelinks%2Furls&callback=JSON_CALLBACK';
$http({
url: wikiDataString,
method: 'jsonp'
})
.success(function(response2) {
$scope.jason2 = response2;
var url = response2.entities["Q" + items].sitelinks.enwiki.url;
var wikipediaTitle = url.substr(24, url.length);
var wikipediaURL = 'http://en.wikipedia.org/w/api.php?action=query&prop=extracts|info&exintro&titles=' + wikipediaTitle + '&format=json&explaintext&redirects&inprop=url&indexpageids&format=json&callback=JSON_CALLBACK';
$http({
url: wikipediaURL,
method: 'jsonp'
}).success(function(response4) {
var query = response4.query;
var pageID = response4.query.pageids;
var title = response4.query.pages[pageID].title;
var fullurl = response4.query.pages[pageID].fullurl;
var content = response4.query.pages[pageID].extract;
$scope.title = title;
$scope.content = content;
$scope.fullurl = fullurl;
$scope.jason = query;
});
});
});
}]);
950273 is the Wikidata entity ID. You find the entity itself at https://www.wikidata.org/wiki/Q950273
By using that you can query Wikidata for the articles connected to it using the API and the action wbgetentities and ask for sitelinks and sitelinks/url like this: http://wikidata.org/w/api.php?action=wbgetentities&format=json&ids=Q950273&props=sitelinks%7Csitelinks%2Furls
Or try going to the language version of your choice directly using Special:GoToLinkedPage. Eg. https://www.wikidata.org/wiki/Special:GoToLinkedPage/enwiki/Q950273
I'm trying to create a website where users can come and look for a set of resources, something like a portal, or a database like JSTOR. I am using Weebly; this website will eventually be turned over to someone who does not know computers well, so I'm trying to keep things simple (and free, where doable).
My thought was to use Google Spreadsheets/Forms to handle the input and storage of the data for each individual resources (Title, Author, Type, Topic, Country, etc.), and then find some some method of creating a search function that could placed on the website. Any user could arrive at the site, put in whatever criteria they want to look for, and any resources in the database would be listed out for the user to further investigate. Users would not be adding data to the spreadsheets; only querying it for data.
My first question is such a script/arrangement possible and can it be embedded into a website page? My second question is what would the best approach be?
Yes this is certainly possible, but can achieved in a variety of ways.
One approach you could take with this is to retrieve all the data from the spreadsheet as JSON format and add it to the DOM as a HTML table. Then you can use a nice plugin like dataTables which has a pretty good native search function. I'll give a basic example below.
To retrieve the data you can use Googles spreadsheet JSON API. A basic example is below.
<script src="http://spreadsheets.google.com/feeds/cells/*ID*/*WS*/public/values?alt=json-in-script&callback=*FN*"></script>
Where ID is the spreadsheet's long ID.
Where WS is the worksheet number e.g. 1,2,3 etc.
Where FN is the function you want to call. In my below function i use importGSS
Then I've written the below script that adds the data to a HTML table. It first adds the first row to a <thead> section and then adds the rest to the <tbody> section.
function cellEntries(json, dest) {
var table = document.createElement('table');
var thead = document.createElement('thead');
var tbody = document.createElement('tbody');
var thr;
var tr;
var entries = json.feed.entry;
var cols = json.feed.gs$colCount.$t;
for (var i=0; i <cols; i++) {
var entry = json.feed.entry[i];
if (entry.gs$cell.col == '1') {
if (thr != null) {
tbody.appendChild(thr);
}
thr = document.createElement('tr');
}
var th = document.createElement('th');
th.appendChild(document.createTextNode(entry.content.$t));
thr.appendChild(th);
}
for (var i=cols; i < json.feed.entry.length; i++) {
var entry = json.feed.entry[i];
if (entry.gs$cell.col == '1') {
if (tr != null) {
tbody.appendChild(tr);
}
tr = document.createElement('tr');
}
var td = document.createElement('td');
td.appendChild(document.createTextNode(entry.content.$t));
tr.appendChild(td);
}
$(thead).append(thr);
$(tbody).append(tr);
$(table).append(thead);
$(table).append(tbody);
$(dest).append(table);
$(dest + ' table').dataTable();
}
You can then call back the function with ... where #Destination is the <div> you want to add the HTML table to.
function importGSS(json){
cellEntries(json, '#Destination');
};
Once all completed you'll see something like the below screenshot, the top the final results and the bottom the original spreadsheet. I've edited out some information. I hope this has been of some help.