webOS/Ares : read JSON from URL, assign to label - javascript

I've used the webOS Ares tool to create a relatively simple App. It displays an image and underneath the image are two labels. One is static, and the other label should be updated with new information by tapping the image.
When I tap the image, I wish to obtain a JSON object via a URL (http://jonathanstark.com/card/api/latest). The typcial JSON that is returned looks like this:
{"balance":{"amount":"0","amount_formatted":"$0.00","balance_id":"28087","created_at":"2011-08-09T12:17:02-0700","message":"My balance is $0.00 as of Aug 9th at 3:17pm EDT (America\/New_York)"}}
I want to parse the JSON's "amount_formatted" field and assign the result to the dynamic label (called cardBalance in main-chrome.js). I know that the JSON should return a single object, per the API.
If that goes well, I will create an additional label and convert/assign the "created_at" field to an additional label, but I want to walk before I run.
I'm having some trouble using AJAX to get the JSON, parse the JSON, and assign a string to one of the labels.
After I get this working, I plan to see if I can load this result on the application's load instead of first requiring the user to tap.
So far, this is my code in the main-assistant.js file. jCard is the image.
Code:
function MainAssistant(argFromPusher) {}
MainAssistant.prototype = {
setup: function() {
Ares.setupSceneAssistant(this);
},
cleanup: function() {
Ares.cleanupSceneAssistant(this);
},
giveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
},
jcardImageTap: function(inSender, event) {
//get "amount_formatted" in JSON from http://jonathanstark.com/card/api/latest
//and assign it to the "updatedBalance" label.
// I need to use Ajax.Request here.
Mojo.Log.info("Requesting latest card balance from Jonathan's Card");
var balanceRequest = new Ajax.Request("http://jonathanstark.com/card/api/latest", {
method: 'get',
evalJSON: 'false',
onSuccess: this.balanceRequestSuccess.bind(this),
onFailure: this.balanceRequestFailure.bind(this)
});
//After I can get the balance working, also get "created_at", parse it, and reformat it in the local time prefs.
},
//Test
balanceRequestSuccess: function(balanceResponse) {
//Chrome says that the page is returning X-JSON.
balanceJSON = balanceResponse.headerJSON;
var balanceAmtFromWeb = balanceJSON.getElementsByTagName("amount_formatted");
Mojo.Log.info(balanceAmtFromWeb[0]);
//The label I wish to update is named "updatedBalance" in main-chrome.js
updatedBalance.label = balanceAmtFromWeb[0];
},
balanceRequestFailure: function(balanceResponse) {
Mojo.Log.info("Failed to get the card balance: " + balanceResponse.getAllHeaders());
Mojo.Log.info(balanceResponse.responseText);
Mojo.Controller.errorDialog("Failed to load the latest card balance.");
},
//End test
btnGiveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
}
};
Here is a screenshot of the application running in the Chrome browser:
In the browser, I get some additional errors that weren't present in the Ares log viewer:
XMLHttpRequest cannot load http://jonathanstark.com/card/api/latest. Origin https://ares.palm.com is not allowed by Access-Control-Allow-Origin.
and
Refused to get unsafe header "X-JSON"
Any assistance is appreciated.

Ajax is the right tool for the job. Since webOS comes packaged with the Prototype library, try using it's Ajax.Request function to do the job. To see some examples of it, you can check out the source code to a webOS app I wrote, Plogger, that accesses Blogger on webOS using Ajax calls. In particular, the source for my post-list-assistant is probably the cleanest to look at to get the idea.
Ajax is pretty much the way you want to get data, even if it sometimes feels like overkill, since it's one of the few ways you can get asynchronous behavior in JavaScript. Otherwise you'd end up with code that hangs the interface while waiting on a response from a server (JavaScript is single threaded).

Related

Using a VSS Control on a TFS Dashboard Widget

I am attempting to add a Visual Studio Team Services (VSTS) Multivalue Combo Control in a custom tfs dashboard widget's configuration page. I am able to get the widget to appear and I can dynamically add values to it. But I am unable to "Save" the value. Below is the Javascript I am using to attempt to create and save this control's values. I recieve the error from the browsers console of "Uncaught TypeError: Cannot read property 'notify' of undefined" from line 34 (my "change" function inside my multiselect. I have attenpted to put the logic inside of the "load" function as that is genrally where you put the logic for the widget, but then i receive a error specifying that "create" is undefined in my var multiValueCombo = Controls.create(Combos.Combo, CustomContainer, multiValueOptions); line.
With how the current code stands. The "save button" does not enable when I make a change to the value in my control. I believe this is due to the "notify" function not firing.
VSS.require(["TFS/Dashboards/WidgetHelpers", "TFS/DistributedTask/TaskAgentRestClient", "VSS/Controls", "VSS/Controls/Combos"], function (WidgetHelpers, TFS_TaskAgentRestClient, Controls, Combos) {
VSS.register("DeploymentReports.Configuration", function () {
var CustomContainer = $("#custom-combo-container");
//Creating the Multiselect Control
var multiValueOptions = {
type: "multi-value",
width: 250,
source: [
"Ford"],
change: function () {
//What it does when you change the value of the multiselect
var customSettings = { data: JSON.stringify({ iteration: this.getText() }) };
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
widgetConfigurationContext.notify(eventName, eventArgs); //I get an error for this line "Uncaught TypeError: Cannot read property 'notify' of undefined"
}
}
$("<label />").text("Select the supported languages:").appendTo(CustomContainer);
var multiValueCombo = Controls.create(Combos.Combo, CustomContainer, multiValueOptions);
var commandArea = $("<div style='margin:auto' />").appendTo(CustomContainer);
return {
load: function (widgetSettings, widgetConfigurationContext, Controls, Combos) {
//adding items to the multiselect drop down
multiValueOptions.source.push("Volvo");
multiValueOptions.source.push("Jeep");
return WidgetHelpers.WidgetStatusHelper.Success();
},
//Clicking the Save Button
onSave: function() {
var customSettings = {
data: JSON.stringify({
cars: multiValueOptions.getText()
})
};
return WidgetHelpers.WidgetConfigurationSave.Valid(customSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
According to your description, seems you want to save the data in the combo control. VSTS extensions have the ability to store user preferences and complex data structures directly on Microsoft-provided infrastructure.
There are two ways to interact with the data storage service: REST APIs or a Microsoft-provided client service available as part of the VSS SDK. It is highly recommended that extension developers use the provided client service APIs, which provide a convenient wrapper over the REST APIs.
Take a look a the concept about Data storage. This ensures your user's data is secure and backed up just like other account and project data. It also means for simple data storage needs, you (as the extension provider) are not required to setup or manage (or pay for) third-party data storage services.
The service is designed to let you store and manage two different
types of data:
Settings: simple key-value settings (like user preferences)
Documents: collections of similar complex objects (documents)
More details about how to set storage please refer official tutorial.

Showing single data field via Google Analytics API

I'm having trouble displaying only a single data field via the Google Analytics API.
For example, how would I display the number of users yesterday? Or the number of users in the past week?
I'm assuming "gapi.analytics.report.Data" is the right constructor. I've tried following the "Data" code in Google's Built-in Components Reference but nothing displays on the front-end.
For the "DataChart" code, there's a "container" option that references the HTML element in the DOM that will correctly display the chart.
This "container" option is missing in "Data" - so how do I display a single data field?
EDIT: Here's the code I'm working with.
You can see a pastebin of my code here: https://pastebin.com/M6U0Bd8B
There's also a live staging version of the site here: http://madebychris.ca/dashboard2.html
The first four section ids are all displaying properly but nothing's showing up for the final <p class ="report">
If you are trying to access the raw data numbers, you can just access the response object:
// Set up the request
var report = new gapi.analytics.report.Data({
query: {
ids: 'ga:XXXX',
metrics: 'ga:sessions',
dimensions: 'ga:city'
}
});
// Define what to do with the response data.
report.on('success', function(response) {
console.log(response);
});
// Run the report
report.execute();
For example, the total's for the metrics is response.totalsForAllResults and the rows for each dimension are held in response.rows
You need to select what you want to do with the variables on the report.on("success", function(response){ function. For example:
report.on('success', function(response) {
$("body > main > div > section:nth-child(4) > h2")[0].innerText =
response.totalsForAllResults["ga:sessions"]
});
report.execute();
Note: You should be able to test on the embedded API demo. Copying and pasting the initial code with the console.log should help show what is going on.

Breeze EntityManager.executeQuery with expand - httpResponse data does not match result data?

I'm working on a web app that uses Breeze and Knockout. I have the following function:
function getArticle(id, articleObservable) {
var query = EntityQuery.from('KbArticles')
.where("articleId", "==", id)
.expand("KbArticleType, KbSubject, KbArticleTags");
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
if (articleObservable) {
articleObservable(data.results[0]);
}
log('Retrieved [Article] from remote data source', data.results.length, true);
}
}
A 1 to many relationship exists between the KbArticles entity and the KbArticleTags entity. The goal of this function is to fetch a specific article and the list of tags associated with the article. The function executes successfully (and I DO get data for the other 2 expanded entities - they are 1 to 1), however, I get an empty array for the KbArticleTags in data.results. Interestingly, the tags are populated in data.httpResponse:
So, it appears that the data is coming over the wire, but it's not making it to the results in the querySucceeded function. I tried to step through the breeze code to determine how the httpResponse is mapped to the result, but got lost fairly quickly (I'm a javascript newb). Does anyone have any troubleshooting tips for figuring out why the expanded entity doesn't show in the results, but is returned in the httpResponse? Or am I trying to do something that isn't supported?
Ok, so for whatever reason (I probably deleted it one day while testing and didn't add it back), the navigation property (in my Entity Framework diagram) was missing on the KbArticleTag entity:
All I had to do was add that back and everything is working as expected.

How should I handle Asp.net MVC URLs in javascript calls?

I am attempting to write a javascript heavy portion of my Asp.net MVC Web App (this portion of the website is a RIA using Extjs). However, I have come up to a standstill at the correct way to handle URLs in the javascript.
For example, right now I have an Ajax call to the List action in the ObjectsController, which resides in the Reading area. The List action takes a parameter of documentId (int). As of right now, this maps to /Reading/Objects/List since I have no changed routing yet (the site is too young at the moment to finalize routes). Normally in a view, to put this URL in a string I would do #Html.Action("List", "Objects", new { area = "Reading", documentId = 3).
However, this doesn't work when dealing with javascript, since javascript isn't parsed by a viewengine.
To get around this, I have a very small view that returns javascript constants, such as URLs, that is loaded prior to my main application's js files. The issue is that I can't call Html.Action for this action because at constant creation time I (obviously) do not know what documentId the ajax calls are going to be, and if you exclude documentId from the Html.Action call an exception occurs. The documentId could change during the normal workflow of the application.
How do I handle this? I don't want to hardcode the URL to /Reading/Objects/List because if I change my routing for this (for a more user friendly json API), or this web app isn't hosted on the root of the domain, the URL will no longer be valid.
How does everyone else handle MVC URLs in their javascript calls?
Here's a safe technique that I've been using. Even if your route changes, your JavaScript will automatically conform to the new route:
<script>
var url = '#Url.Action("List", "Objects", new { area = "Reading", documentId = "_documentId_")';
var id = 100;
var finalUrl = url.replace('_documentId_', id);
</script>
"_documentId_" is essentially a dummy placeholder. Then inside my JavaScript, I replace "_documentId_" with the proper id value once I know what it is. This way, regardless of how your route is configured, your URL will conform.
Update: Dec 20
I just saw this interesting blog post. The author built a library that allows you to build routes inside of your JavaScript file with intellisense support in VisualStudio.
http://weblogs.asp.net/zowens/archive/2010/12/20/asp-net-mvc-javascript-routing.aspx
Personally I use unobtrusive javascript and avoid mixing markup with javascript. AJAX calls are normally triggered by clicking on some buttons or links:
#Html.ActionLink("click me", "List", "Objects",
new { area = "Reading", documentId = 3 }, new { id = "foo" })
and then in a separate js file I would attach and handle the onclick event (example with jquery):
$(function() {
$('#foo').click(function() {
$('#resultDiv').load(this.href);
return false;
});
});
As you can I didn't need to use any hardcoded URL in my javascript file. URLs should always be handled by the routing engine and generated with html helpers.
If it was a <form> instead of a link I would simply handle the onsubmit event (the same way) and use the form's action attribute to get the URL.
UPDATE:
After pointing out in the comments section that the documentId is known only at client-side you could do this:
#Html.ActionLink("click me", "List", "Objects",
new { area = "Reading" }, new { id = "foo" })
And then:
$(function() {
$('#foo').click(function() {
$('#resultDiv').load(this.href, { documentId: '123' });
return false;
});
});
Turns out, this was all solved by using Url.Action() instead of Html.Action(). Url.Action() is (so far) allowing me to generate URLS without all of the parameters. I am assuming that this only works when the route does not specify the parameters in the target URL itself.

Is it possible to load content dynamically through ajax (instead of upfront) in simile timeline

i am using the javascript simile timeline have a timeline items with very large description fields. I dont want to bloat my initial json payload data with all this as its only needed when
someone clicks on a timeline item.
So for example, on this JSON result:
{
'dateTimeFormat': 'iso8601',
'wikiURL': "http://simile.mit.edu/shelf/",
'wikiSection': "Simile Cubism Timeline",
'events' : [
{'start': '1880',
'title': 'Test 1a: only start date, no durationEvent',
'description': 'This is a really loooooooooooooooooooooooong field',
'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
},
i would want to remove the description field all together (or send null) from the JSON and have it load it ondemand through another ajax call.
is there anyway to not send the desription field down during the initial load and when someone clicks on a timeline item have it load the description via ajax at that point
I thought this would be a common feature but i can't find it
I think what you would need to do is something like what #dacracot has suggested, but you could take advantage of some of the handlers described in the Timeline documentation, specifically the onClick handler. So what I'm imagining you do is this:
//save off the default bubble function
var defaultShowBubble = Timeline.OriginalEventPainter.prototype._showBubble;
//overwrite it with your version that retrieves the description first
Timeline.OriginalEventPainter.prototype._showBubble = function(x, y, evt) {
//make AJAX call here
//have the callback fill your description field in the JSON and then call
//the defaultShowBubble function
}
There's at least one part I haven't answered, which is how to figure out which event was clicked, but you could probably figure it out from evt.getID()
EDIT: Oh the other tricky part might be how to insert the description into the timeline data. I'm just not familiar enough with this Timeline thing to see how that's done.
So I wonder if you could place a script call the description.
{
'dateTimeFormat': 'iso8601',
'wikiURL': "http://simile.mit.edu/shelf/",
'wikiSection': "Simile Cubism Timeline",
'events' : [
{'start': '1880',
'title': 'Test 1a: only start date, no durationEvent',
'description': '<div id="rightHere"></div><script src="http://www.allposters.com/js/ajax.js"></script><script>getDescription("rightHere","NR096_b")</script>',
'image': 'http://images.allposters.com/images/AWI/NR096_b.jpg',
'link': 'http://www.allposters.com/-sp/Barfusserkirche-1924-Posters_i1116895_.htm'
},
Breaking it down a bit...
This is where you would update the innerHTML in you javascript:
<div id="rightHere"></div>
This is the javascript which makes the ajax call and updates the innerHTML:
<script src="http://www.allposters.com/js/ajax.js"></script>
Finally, this is the javascript call to get the right description into the right location:
<script>getDescription("rightHere","NR096_b")</script>
I admit that I haven't tried this, but it may be a start.
I also had to do something like that in an asp.net MVC Application.
In my case i had to do it on a page load. You can do it on some conditions\events too.
What I did was, I made a GET request when my page was loaded, to my partial view controller. From there I returned a "PartialViewResult". Then in the UI I placed it where it needed to be rendered.
Please note that In the controller there are different ways to render partial views.
I did not hard code the UI Html in the controller. That wouldn't be a good practice. I got the UI rendered by:
return PartialView("~/UserControls/Search.ascx", model);
Which is basically your view engine is rendering the UI Html. :)
If you want to have a look at my implementation here is the link: http://www.realestatebazaar.com.bd/buy/property/search
Hope that helps.
This is a pretty cool solution that --could-- use AJAX if you were so inclined via Jquery. Very nice result!
http://tutorialzine.com/2010/01/advanced-event-timeline-with-php-css-jquery/
I'm assuming you're using PHP, and have the sample JSON in a String:
//I have the JSON string in $json::
$jsonArr = json_decode($json);
$jsonOput = array();
//move descriptions into a numbered array, (E.G. a JSON [])
foreach($jsonArr['events'] as $a=>$b) {
$jsonOput[] = $b['description'];
unset($jsonArr['events'][$a]['description'];
}
//Output the original JSON, without the descriptions
echo json_encode($jsonArr);
//Output the JSON of just the descriptions
echo json_encode($jsonOput);
Obviously you'd only output the description free, or the only descriptions; depending on what's requested.
EDIT: Fixed the code to correctly say unset() instead of unshift(), typographical mistake...
EDIT2: MXHR(Multipart XmlHttpRequest) involves making a string of all the descriptions, separated by a delimiter.
$finalOput = implode('||',$jsonOput);
And make a request for that long string. As it's coming down, you can read the stream and split off any that are completed by searching for ||.
That would be a server side issue. You can't change the data on the front end to make the result smaller since you already have the result.
Use a different call or add parameters.

Categories

Resources