I know this is probably a common question but I had issues getting any solutions to work with my use case. I have a calendar widget I have forked on Codepen made using JS. I want to replace the default data with my Firebase database but the JSON structure is different and breaks the Calendar function. My JSON in Firebase is as follows:
{
"Events" : {
"cool event" : {
"calendar" : "Other",
"color" : "yellow",
"date" : "2017-01-13",
"eventName" : "new"
}
},
The original method that the widget received data was as so:
var data = [
{ eventName: 'Lunch Meeting w/ Mark', calendar: 'Work', color: 'orange', date: '2014-02-08' },]
How can I format either my data or modify the function to accept my data structure? Keep in mind, Firebase does not allow a simple array and stores them as objects...
Here is a CodePen: http://codepen.io/Auzy/pen/OWJxqO
One way would be to transform your data to an array of the required format
For example
var firebase = {
"Events" : {
"cool event" : {
"calendar" : "Other",
"color" : "yellow",
"date" : "2017-01-13",
"eventName" : "new"
}
}
};
var data = [];
for(event in firebase.Events){
data.push(firebase.Events[event])
}
console.log(data)
Update
Firebase api is asynchronous, so you need to wait for the data (using the .once('value').then(..)) to return and then transform the data (which you actually do not need since firebase provides an iterator) and then initialize the calendar.
So you need to change your code to
var stuff = firebase.database().ref().child("Events");
var data = [];
stuff.once('value').then(function(snapshot){
snapshot.forEach(function(event){
data.push( event.val() );
})
var calendar = new Calendar('#calendar', data);
});
(and remove the initialization from the bottom of the code as it has been inserted in the callback)
Related
Here is my JSON and Code which gives only array but not it values. As I had used push it generating Unique Id from, which I am not getting. All the values that stored in that id.
{
"nitin" : [ {
"mobile" : {
"-K7GalDi5aAahDENCRi" : {
"name" : "file:///D:/Software%20Drive/addItem.html?category=mobile",
"price" : 345,
"quantity" : 34
}
},
"perfume" : {
"-K7K7HSu4rQNwbH3ud0H" : {
"name" : file:///D:/Software%20Drive/addItem.html?category=perfume",
"price" : 1000,
"quantity" : 20
}
}
}]
}
This is my code
fbref.on("value", function(snapshot) {
var newPost = snapshot.val();
console.log(newPost);
fbref.on("child_added", function(newPost,pre){
newchild=newPost.val();
console.log(newchild);
var n=newPost.key();
console.log("this is key"+n);
console.log("Name"+newchild.name);
console.log("Price"+newchild.price);
console.log("Quantity"+newchild.quantity);
});
});
The child_added event will fire when a child node is added directly under the location that you're querying.
So if you're querying the root of the JSON you show, a child_added will fire for nitin. And then if we'd add puf, a child_added will fire for that too.
{
"nitin" : [ {
...
}],
"puf": [ {
...
}],
}
If you want to receive a child_added for items inside mobile or perfume, you will need to attach a child_added on the parent node of those:
fbref.child('nitin').child(0).child('mobile').on('child_added'...
Or:
fbref.child('nitin/0/mobile').on('child_added'...
See this jsbin for a working sample of this.
I want to retrieve consumerfinance.gov complaintdatabase data using the Socrata API.
This is straightforward to retrieve the data using the instructions on the site at http://www.consumerfinance.gov/complaintdatabase/technical-documentation/#api-documentation
I used the following query with '6yuf-367p' to get just 'prepaid card' product data and the '.json' tag to get it in JSON format:
http://data.consumerfinance.gov/api/views/6yuf-367p/rows.json
I used PHP to retrieve data with this query:
$url = "http://data.consumerfinance.gov/api/views/6yuf-367p/rows.json";
$json = file_get_contents($url);
$data = json_decode($json);
var_dump($data);
The results are paraphrased below. A couple of things about the results that are different than what I was expecting.
I wasn't expecting the 'Meta' section. The column names are in the Meta section not associated directly with the data in { key: value } format.
I was expecting the Data section to have { key: value } format instead of just 'values'. This is different than the format described on Socrata help page at
http://dev.socrata.com/docs/formats/json.html
I am not advanced javascript developer so I am wondering how best to proceed. Ideally I want only the 'Data' section with column names in the { key: value } format. I wanted it in that { key: value } format to use with things like Google Charts.
I am imaging I would have to save the column names in array and then loop through each data row and rewrite the data rows with column names included to get { key: value } format.
My other option would be to use the csv API format which is super clean with nice clean columns and no Meta section. But then I would have to convert the csv to JSON which seems unnecessary as the JSON is available.
CSV query is this:
http://data.consumerfinance.gov/api/views/6yuf-367p/rows.csv
So couple of questions:
Does socrata provide an API feed without the 'Meta' section? Is there a filter I can use to exclude the 'Meta' section?
If answer to #1 is no, does Socrata have ready javascript to parse the JSON to get the 'Data' section in { key: value } format similar format as described on Socrata help page?
Thanks!
{
"meta" : {
"view" : {
"id" : "6yuf-367p",
"name" : "Prepaid Card Complaints",
"averageRating" : 0,
"createdAt" : 1434039311,
etc etc
"columns" : [ {
"id" : -1,
"name" : "sid",
"dataTypeName" : "meta_data",
"fieldName" : ":sid",
"position" : 0,
"renderTypeName" : "meta_data",
"format" : {
}
}, {
etc etc
"data" : [ [ 208134, "A7A3941C-A764-44CA-ABC0-66DE814F1969", 208134, 1438091214, "924763", 1438091214, "924763", null, "2015-07-13T00:00:00", "Prepaid card", "General purpose card", "Managing, opening, or closing account", null, null, null, "Amex", "WA", "982XX", "Web", "2015-07-19T00:00:00", "Closed with monetary relief", "Yes", null, "1464043" ]
......
]
}
It looks like you grabbed the wrong JSON URL. The one you grabbed is for the JSON export, which will dump you the entire dataset in a JSON format along with all of the metadata, and it doesn't provide a queryable API endpoint.
Instead, you should use the endpoint https://data.consumerfinance.gov/resource/jhzv-w97w.json. That'll get you the {"key" : "value"} pairs you're looking for, like this:
[ {
"zip_code" : "982XX",
"complaint_id" : "1464043",
"issue" : "Managing, opening, or closing account",
"date_received" : "2015-07-13T00:00:00",
"state" : "WA",
"product" : "Prepaid card",
"company_response" : "Closed with monetary relief",
"company" : "Amex",
"submitted_via" : "Web",
"date_sent_to_company" : "2015-07-19T00:00:00",
"sub_product" : "General purpose card",
"timely" : "Yes"
}, ... ]
You can also view API docs for that dataset at: http://dev.socrata.com/foundry/#/data.consumerfinance.gov/jhzv-w97w
Good luck, and let me know if you have more questions.
I have an XMLView home page containing some tiles. These tiles are populated from a JSON file. The tiles have a 'title' attribute which requires i18n data binding.
Part of the XML view:
<TileContainer id="container" tiles="{/TileCollection}">
<StandardTile
icon="{icon}"
title="{title}"
press="onPress" />
</TileContainer>
JSON file:
{
"TileCollection" : [
{
"icon" : "sap-icon://document-text",
"title" : "{i18n>foo}"
},
... etc
The old way I accomplished data binding was directly in the view with title="{i18n>foo}". Of course now I have essentially two layers of data binding, one in the JSON for the i18n, and one in the view to get the JSON (which gets the i18n).
This is also my Component.js where I set up the i18n model.
sap.ui.core.UIComponent.extend("MYAPP.Component", {
metadata: {
rootView : "MYAPP.view.Home", //points to the default view
config: {
resourceBundle: "i18n/messageBundle.properties"
},
... etc
init: function(){
sap.ui.core.UIComponent.prototype.init.apply(this, arguments);
var mConfig = this.getMetadata().getConfig();
var oRouter = this.getRouter();
this.RouteHandler = new sap.m.routing.RouteMatchedHandler(oRouter);
oRouter.register("router");
oRouter.initialize();
var sRootPath = jQuery.sap.getModulePath("MYAPP");
var i18nModel = new sap.ui.model.resource.ResourceModel({
bundleUrl : [sRootPath, mConfig.resourceBundle].join("/")
});
this.setModel(i18nModel, "i18n");
}
This question arose from discussion about another question, so there may be more info there for anyone interested. Link
The approach I usually take is using a formatter function, which sole purpose is to get the correct localized value for a certain key (which is maintained in the resource model, and driven by the data model)
For instance, the Tile UI would look like this:
<TileContainer id="container" tiles="{/tiles}">
<StandardTile
icon="{icon}"
type="{type}"
title="{ path : 'title', formatter : '.getI18nValue' }"
info="{ path : 'info', formatter : '.getI18nValue' }"
infoState="{infoState}"
press="handlePress"/>
</TileContainer>
(Notice the formatter function getI18nValue for properties title and info; these are the properties to be translated. The other properties come as-is from the bound JSONModel)
The model could look like this:
tiles : [
{
icon : "sap-icon://inbox",
number : "12",
title : "inbox", // i18n property 'inbox'
info : "overdue", // i18n property 'overdue'
infoState : "Error"
},
{
icon : "sap-icon://calendar",
number : "3",
title : "calendar", // i18n property 'calendar'
info : "planned", // i18n property 'planned'
infoState : "Success"
}
]
where the title and info property values of the JSONModel (for instance, 'inbox' and 'overdue') correspond with a key in your resourcebundle files (and thus your ResourceModel)
The formatter function in the controller (or better, in a standalone JS file, for re-use in multiple views) is then pretty simple:
getI18nValue : function(sKey) {
return this.getView().getModel("i18n").getProperty(sKey);
}
It does nothing more than supplying the value from the model (for instance, 'inbox') and returning the localized value for this key from the resource model
I have data in firebase that looks like this:
"application": {
"companies": {
"firebase": {
"creation": {
"name": "Firebase Inc",
"location": "USA"
},
"google": {
"creattion": {
"name": "Google Inc",
"location": "USA"
}
}
"facebook": {
},
"apple": {
}
}
}
}
There are tens of thousands of records under companies key. How do i efficiently execute following queries?
How do I query only the records for which key creation is present under their name?
How do I query only the records that DO NOT have key creation present under their name?
I also want to call .on('child_added') on the returned result set so that I can process only those specific records later on. Is it possible?
EDIT: Simpler way without using an extra parameter
Queries
Here are the queries to do this without having to use an extra parameter:
Find the companies without creation:
var ref = new Firebase(fbUrl+'/companies').orderByChild("creation").equalTo(null);
Find the companies with creation:
var ref = new Firebase(fbUrl+'/companies').orderByChild("creation").startAt(!null);
You would add ".indexOn": "creation" to the rules.
Edit 2: I was curious, so I pushed 11,000 records to /companies2 (half with creation children, half without). I was able to retrieve 5500 matching records in ~4 seconds using the above queries (or one of the variants I've shown below).
Edit 3: If you're running these queries frequently, it might be worth it to separate children of /companies into two bins based the presence of creation. That way, you can read the two segments separately without having to rely on queries.
Factory
Here is what the revised factory would look like (I've revised the PLNKR to match):
app.factory("CompaniesFactory",function($q, fbUrl){
return function(hasCreation){
var deferred = $q.defer();
var ref = new Firebase(fbUrl+'/companies').orderByChild("creation");
var query;
if (hasCreation) {
query = ref.startAt(!null);
// or:
// query = ref.startAt(true);
} else {
query = ref.equalTo(null);
// or:
// query = ref.endAt(!null);
// query = ref.endAt(true);
}
query.once("value", function(dataSnapshot){
deferred.resolve(dataSnapshot.val());
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
});
And yes, it is possible to call .on('child_added') on the returned dataSnapshot. See DataSnapshot.ref().
Original answer using an extra parameter:
(Keeping this for reference)
Another way to do it would be by adding another parameter called hasCreation to children of companies that have creation, and query by that.
Data
The query would then be var ref = new Firebase(fbUrl+'/companies').orderByChild("hasCreation").equalTo(hasCreation);
If hasCreation in the query is null, the query will return the companies without a hasCreation child.
If hasCreation in the query is true, the query will return the companies with hasCreation===true.
{
"company1" : {
"creation" : {
"name" : "company1"
},
"hasCreation" : true
},
"company2" : {
"name" : "company2"
},
"company3" : {
"name" : "company3"
},
"company4" : {
"creation" : {
"name" : "company4"
},
"hasCreation" : true
}
}
Rules
You would add the ".indexOn" : "hasCreation" to your rules like so:
"so:29179389":{
".read" : true,
".write" : true,
"companies" : {
".indexOn" : "hasCreation"
}
}
Companies Factory
app.factory("CompaniesFactory",function($q, fbUrl){
return function(hasCreation){
var deferred = $q.defer();
if (!hasCreation) {
hasCreation = null;
}
var ref = new Firebase(fbUrl+'/companies').orderByChild("hasCreation").equalTo(hasCreation);
ref.once("value", function(dataSnapshot){
deferred.resolve(dataSnapshot.val());
});
return deferred.promise;
}
});
Controller
app.controller('HomeController',function($scope,fbUrl,CompaniesFactory) {
$scope.getCompanies = function(hasCreation) {
var companies = new CompaniesFactory(hasCreation).then(function(data){
console.log(data);
$scope.companies = data;
});
}
});
HTML
<body ng-app="sampleApp">
<div ng-controller="HomeController">
<button ng-click="getCompanies(true)">Find with creation</button>
<button ng-click="getCompanies(false)">Find without creation</button>
<h2>Companies:</h2>
{{companies}}
</div>
</body>
What I would do, is I would set a condition to verify if your xxx.firebaseio.com/Application/companies/______/creation exists. In a empty blank, you can set for loop to irritate over the array of companies.Then, you can create two arrays with angular.forEach: one including those companies which do have 'creation', and the other array in which the elements do not include the 'creation'.
Hope that helps :)
Edit:
There is another approach to this question, in this thread:
Angularfire: how to query the values of a specific key in an array?
I am beginner in Javascript/jQuery and I am working on an interface made with KnockoutJS, so I have several models. I would like to save all the data in the database but I don't know how to do it.
I started with :
self.save = function() {
var data = ko.toJS(self);
var test = ko.toJSON(self);
console.log(test);
}
$.ajax({
url: "myURL",
data: {'carrier': data.carrier},
type: "POST",
});
and this is the result of the console.log :
{"id":1,"carrier":"1","Settings":[{"id":1,"price":{"id":1,"DeliveryStandard":"3.00","DeliveryExpress":"6.00","Details":{"id":1,"Standard":[{"id":1,"fromPrice":0,"maxPrice":"45.000"}],"Express"[{"id":1,"fromPrice":0,"maxPrice":"66.000"}]}}}}]}
I can get the value of carrier by using data.carrier but I don't know how to get the other data like DeiveryStandard, DeliveryExpress, fromPrice, maxPrice ...
Have you got an idea?
Thanks you in advance, and sorry if my question is silly!
If you format your JSON into a more readable format, with indenting, it makes it a lot easier to understand:
(though it should be noted that it is only technically JSON while in a string format, outside of that it is just a standard javascript object)
{
"id":1,
"carrier":"1",
"Settings":[
{
"id":1,
"price": { "id":1,
"DeliveryStandard":"3.00",
"DeliveryExpress":"6.00",
"Details": { "id":1,
"Standard": [{"id":1,
"fromPrice":0,
"maxPrice":"45.000"
}],
"Express" //Missing semi-colon
[{"id":1,
"fromPrice":0,
"maxPrice":"66.000"
}]
}
}
}}//One too many closing braces
]
}
First thing to note is you have 2 syntax errors, highlighted above with comments. So fix them first! (Though I wonder if they are typos as you seem to have it working at your end)
Then we can look at the structure tree to work out where the values you want are...
DeiveryStandard and DeliveryExpress are both properties of an object assigned to price, which it a property of the first item in the Settings array. So you can access them like so:
var DeliveryStandard = data.Settings[0].price.DeliveryStandard;
var DeliveryExpress= data.Settings[0].price.DeliveryExpress;
fromPrice and maxPrice are found multiple times, in both Standard and Express items. So you need to decide what version you need. If you want Standard then you can get the first item of the Standard array like so:
var standardObject = data.Settings[0].price.Details.Standard[0];
Which you can then access the properties of like:
var fromPrice = standardObject.fromPrice;
var maxPrice = standardObject.maxPrice;
I am sure you can work out how to get the Express version of the same data!
From what you seem to have been able to work out on your own, I think your problem is not knowing how to deal with the arrays. Note that arrays are defined with square brackets [], and elements within an array should be accessed with a zero-based index, for example: array[0] for the first element, and array[1] for the second element.
This should work.
console.log(data.Settings[0].price.DeliveryStandard);
Fixed some errors in your JSON.
var j = {
"id" : 1,
"carrier" : "1",
"Settings" : [{
"id" : 1,
"price" : {
"id" : 1,
"DeliveryStandard" : "3.00",
"DeliveryExpress" : "6.00",
"Details" : {
"id" : 1,
"Standard" : [
{
"id" : 1,
"fromPrice" : 0,
"maxPrice" : "45.000"
}
],
"Express": [
{
"id" : 1,
"fromPrice" : 0,
"maxPrice" : "66.000"
}
]
}
}
}
]
};
alert(j.Settings[0].price.DeliveryStandard);
alert(j.Settings[0].price.DeliveryExpress);
alert(j.Settings[0].price.Details.Standard[0].fromPrice);
alert(j.Settings[0].price.Details.Standard[0].maxPrice);