How to load JSON data into an A-Frame component? - aframe

What's the best way to load a custom JSON file as data into an A-frame component ? For example, the JSON file may contain coordinates of points. I want to load the file as an asset and use the parsed json object in the component.
{"coordinates": [{"x": 0, "y": 1, "z": 2}, // ...]}

You can define your own property type in the schema that parses data how you wish.
To parse JSON from a component, create a parse function that does a JSON.parse:
AFRAME.registerComponent('foo', {
schema: {
jsonData: {
parse: JSON.parse,
stringify: JSON.stringify
}
}
});
Then use the component:
el.setAttribute('foo', 'jsonData', yourJsonData);
Or:
<a-entity foo='jsonData: {"coordinates": [{"x": 0, "y": 1, "z": 2}]}'></a-entity>

Another way is to set your component to have no schema so it just takes an object. There is no API to have a "wildcard" schema yet, but one way is to have a property type that parses the inline-CSS-like string with the styleParser:
AFRAME.registerComponent('foo', {
schema: {
parse: AFRAME.utils.styleParser.parse
}
});
The above component is a single-property schema, so whatever object we pass will become the value of this.data:
el.setAttribute('foo', {bar: 'baz', qux: 'qaz', whateverWeWant: true});
Or:
<a-entity foo="bar: baz; qux: qaz: whateverWeWant: true"></a-entity>

Related

Using reference funtion in an ARM template parameter file

Is there anyway to use the reference funtion in an ARM parameter file? I understand the following can be used to retrieve the intrumentation key of an app insights instance but this doesnt seem to work in a parameter file.
"[reference('microsoft.insights/components/web-app-name-01', '2015-05-01').InstrumentationKey]"
I currently set a long list of environment variables using an array from a parameter file and need to include the dynamic app insights instrumentation key to that list of variables.
Unfortunately, no.
Reference function only works at runtime. It can't be used in the parameters or variables sections because both are resolved during the initial parsing phase of the template.
Here is an excerpt from the docs and also how to use reference correctly:
You can't use the reference function in the variables section of the template. The reference function derives its value from the resource's runtime state. However, variables are resolved during the initial parsing of the template. Construct values that need the reference function directly in the resources or outputs section of the template.
Not in a param file... it's possible to simulate what you want by nested a deployment if that's an option. So your param file can contain the resourceId of the insights resource and then a nested deployment can make the reference call - but TBH, probably easier to fetch the key as a pipeline step (or similar).
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"insightsResourceId": {
"type": "string",
"defaultValue": "'microsoft.insights/components/web-app-name-01'"
}
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Resources/deployments",
"name": "nestedDeployment",
"properties": {
"mode": "Incremental",
"parameters": {
"instrumentationKey": {
"value": "[reference(parameters('insightsResourceId'), '2015-05-01').InstrumentationKey]"
}
},
"template": {
// original template goes here
}
}
}
]
}
Way 1
Use the reference function in your parameter file for resources that are already deployed in another template. For that you have to pass the ApiVersion parameter. Refer MsDoc. which follows:
"value": "[reference(resourceId(variables('<AppInsightsResourceGroup>'),'Microsoft.Insights/components', variables('<ApplicationInsightsName>')), '2015-05-01', 'Full').properties.InstrumentationKey]"
You need to change the property that you are referencing from '.InstrumentationKey' to '.properties.InstrumentationKey'.
Refer to Kwill answer for more information.
Way 2
Get the Content of parameter file in PowerShell variable/Object using
$ParameterObject = Get-Content ./ParameterFileName.json
Update the Parameter file values using
#Assign the parameter values using
$ParameterObject.parameters.<KeyName>.value = "your dynamic value"
Pass $parameterObject to -TemplateParameterObject parameter
Refer here
Way 3
You have to Add/Modify the parameter file values using (PowerShell/ Dev lang (like Python, c#,...) ). After changing the parameter file try to deploy it.

Using Flow union types for Redux actions

Following the style of this Facebook app sample using Redux and Flow together, I made an action type in this manner:
type Action =
| { type: 'ADD_FILES', files: Array<{ id: number, file: File }> }
| { type: 'HANDLE_IMAGE_PUBLISHED', id: number, name: string }
| { type: 'SET_IMAGE_UPLOAD_PROGRESS', id: number, progress: number }
;
But I've found that when I try to process my actions with a reducer, Flow complains if I try to access the name or progress properties, saying "Property not found in object type".
That is, in my reducer, if I check that action.type === 'HANDLE_IMAGE_PUBLISHED' and then access action.name, Flow complains. And the same thing goes for for accessing action.progress property when action.type === 'SET_IMAGE_UPLOAD_PROGRESS'. Both these property accesses should be legit under their respective circumstances, as far as I can tell, but Flow complains.
Yet for some reason it's OK for me to access action.id anywhere, even though one of the types in my union doesn't specify an id property. I'm very confused.
Here is a live demo in the Flow REPL. What am I doing wrong?
This is simply a case of a type refinement invalidation:
https://flow.org/en/docs/lang/refinements/#toc-refinement-invalidations
Because you are using the value in a callback, Flow pessimistically assumes that you could have re-assigned action before the callback runs (it does not know that the map callback is called immediately). It also does not do the analysis to see that there is no place, in fact, that you re-assign it.
All that's needed is to pull the action out as a const:
export default (state: Array<ImageRecordModel> = [], action_: Action): Array<ImageRecordModel> => {
const action = action_;
(tryflow link)
You may also want to consider enabling const params in your .flowconfig. This does basically what you expect: treats all params as const:
[options]
experimental.const_params=true

Add source to existing layer in mapbox GL

The title pretty much says what I intend to do.
I am using Firebase as backend for markers on a map and use the on('child_added') method to monitor these. For every node on a specific location in the database, the on('child_added') will fire once.
This also applies to new nodes being created, hence this is perfect for asynchronously adding new markers to the map as they are added to the database.
In order display these on a map, mapbox GL requires me to transform the data to geojson, create a source and then add this source to a layer. The code below shows this and it actually displays the markers on the map.
markersRef.on('child_added', function(childSnapshot) { //fires once for every child node
var currentKey = childSnapshot.key; //the key of current child
var entry = childSnapshot.val(); //the value of current child
//creates a geojson object from child
var geojson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [entry.position.long, entry.position.lat]
}
}],
"properties": {
title: entry.title,
text: entry.text
}
};
//creates a source with the geojson object from above
map.addSource(currentKey, { //currentKey is the name of this source
"type": "geojson",
"data": geojson,
cluster: true //clusters the points in this source
});
//adds the source defined above to a layer that will be displayed on a map
map.addLayer({
"id": currentKey, // Sets id as current child's key
"source": currentKey, // The source layer defined above
});
});
The problem is that the markers will be in individual sources, making them appear on different layers. Therefore, I cannot cluster them or e.g. search across them.
What I look for is a way to add a source to an existing layer. This would enable me to create a layer outside the on('child_added') method and then add the sources to this layer.
I have looked at the mapbox GL docs but I cannot find anything in there that will enable me to do this. It seems very limited in this respect compared to mapbox js.
I see this as a pretty important feature and don't understand why this is not possible. I hope some of you have a workaround or a way to achieve asynchronously adding markers to a map in mapbox GL.
I have the same problem. I did some searching on this and I found the setData attribute for GeoJSONSource:
https://www.mapbox.com/mapbox-gl-js/api/#geojsonsource#setdata
map.addSource("points", markers);
map.addLayer({
"id": "points",
"type": "symbol",
"source": "points",
"layout": {
"icon-image": "{icon}-15",
"icon-allow-overlap": true,
"icon-ignore-placement": true,
"icon-size": 2,
"icon-offset": [0, -10],
}
});
Then later I update the source, without creating a new layer like so:
map.getSource('points').setData(newMarkers)
So this updates the source without creating a new layer. Then you can search over this layer. The only problem I encountered was that setData erases all the previous data (there is no "addData" functionality) so you need to save the previous markers and add them again. Let me know if you find a workaround for this.
As the documentation at https://www.mapbox.com/mapbox-gl-js/api/#geojsonsource states: A GeoJSON data object or a URL to one. The latter is preferable in the case of large GeoJSON files.
What happens here is that geojson sources loaded via a url are loaded using a background thread worker so they do not affect the main thread, basically always load your data via url or a mapbox style to offload all JSON parsing and layer loading to another thread. Thus anytime you have a change event fired from your firebase monitoring you can simply reload the url you are using to initially load the source.
In addition, the founder of Leaflet and amazing Mapbox Developer Vladimir Agafonkin discusses this here: https://github.com/mapbox/mapbox-gl-js/issues/2289, and it is essentially what they do in their real-time example: https://www.mapbox.com/mapbox-gl-js/example/live-geojson/.
Furthermore, here is an example with socket.io I use client side:
const url = {server url that retrieves geojson},
socket = {setup all your socket initiation, etc};
socket.on('msg', function(data) {
if (data) {
//Here is where you can manipulate the JSON object returned from the socket server
console.log("Message received is: %s", JSON.stringify(data));
if(data.fetch){
map.getSource('stuff').setData(url)
}
} else {
console.log("Message received is empty: so it is %s", JSON.stringify(data));
}
});
map.on('load', function(feature) {
map.addSource('events', {
type: 'stuff',
data: url
});
map.addLayer({
"id": "events",
"type": "symbol",
"source": "events",
"layout": {
"icon-image": "{icon}"
}
});
});

meteor autocomplete server-side

I'm writing a meteor app and I'm trying to add an autocomplete feature to a search box. The data is very large and is on the server, so I can't have it all on the client. It's basically a database of users. If I'm not wrong, the mizzao:autocomplete package should make that possible, but I can't seem to get it to work.
Here's what I have on the server:
Meteor.publish('autocompleteViewers', function(selector, options) {
Autocomplete.publishCursor(viewers.find(selector, options), this);
this.ready();
});
And here are the settings I use for the search box on the client:
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
options: '',
template: Template.vLegend
}],
};
}
But I keep getting this error on the client:
Error: Collection name must be specified as string for server-side search at validateRule
I don't really understand the problem. When I look at the package code, it just seems like it's testing whether the subscription field is a string and not a variable, which it is. Any idea what the problem could be? Otherwise is there a minimum working example I could go from somewhere? I couldn't find one in the docs.
Error: Collection name must be specified as string for server-side search at validateRule
You get this error because you don't specify a Collection name in quotes.
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
collection: 'viewers', // <- specify your collection, in your case it is a "viewers" collection.
options: '',
template: Template.vLegend
}],
};
}
For more information please read here.
Hope this helps!

Mustache JS Template with JSON Collection

Hi this is my first attempt to use MustacheJS with a JSON webservice in .net
Currently I am struggling I can't seem to find what I am doing wrong setting this basic example:
My Webservice is returing the following string:
[
{
"ShortDescription":"BOX",
"Description":"BOXING",
"Id":1
},
{
"ShortDescription":"EPL",
"Description":"ENGLISH PREMIER LEAGUE",
"Id":2
}
]
I have validated its syntax with this website: http://json.parser.online.fr/
and here is the HTML code I am using:
google.load("jquery", "1");
google.setOnLoadCallback(function () {
$(document).ready(
function () {
$.ajax({
url: "../data.asmx/geteagues",
type: "POST",
dataType: "json",
data: "",
contentType: "application/json; charset=utf-8",
success: function (data) {
var template = "<h1>{{ShortDescription}} {{Description}}</h1>";
var html = Mustache.render(template, data);
$('#sampleArea').html(html);
alert(html);
}
})
}
)
});
I am posting the whole JS code, since I am not very good with javascript, basically I want to load always the latest JQuery version from google and then work my WS call.
The problem so far is that when I place a breakpoint in the following line:
var html = Mustache.render(template, data);
I see that the template is setn ok, and so does the data, same value as I posted above, but the .render function is returning: I seems It didnt like the data.
So far all the examples I have seen for inline data come as the following structure:
{
"repo": [
{ "name": "resque" },
{ "name": "hub" },
{ "name": "rip" },
]
}
And then a template defined like this:
{{#repo}}
<b>{{name}}</b>
{{/repo}}
But the only difference of that against my data is that I dont have a "parent" like "repo"
At server side, I am using a .net library called JSON.net and in the documentation of how are collections being serialized:
james.newtonking.com/projects/json/help/html/SerializingCollections.htm
the final result does not include the parent node's name, which I thing is missing from my Mustache Template definition:
[
{
"Name": "Product 1",
"ExpiryDate": "2000-12-29T00:00Z",
"Price": 99.95,
"Sizes": null
},
{
"Name": "Product 2",
"ExpiryDate": "2009-07-31T00:00Z",
"Price": 12.50,
"Sizes": null
}
]
Is this what I am missing? the "repo" parent node from my data so I can iterate my Template?
Thanks in advance for your time.
-ed
Per #stealth on this question Mustache.js: Iterate over a list received via json
{{ #. }}
<b>{{Name}}</b>
{{ /. }}
Note the only difference from #stealth's answer is a "#" instead of "/".
The line data = { 'roles': data }; is the most crucial. Its attaching the key to the data returned by web api or any other source of data like pagemethods or web service
$.ajax({
dataType: "json",
url: '/api/TestApi/GetAllRole',
success: function (data) {
data = { 'roles': data }; // formatting the data to support the mustache format
var html = Mustache.to_html($('#RoleTemplate').html(), data);
$('#tblRole').append(html);
}
});
Few of my articles on the MustacheJs can be found here
INLINE FILTER FOR BASIC GRID USING MUSTACHEJS
http://www.techguides.in/add-inline-filter-to-basic-grid-using-mustache/
Master Details Grid on Demand data loading : Using Mustache.JS
http://www.techguides.in/master-details-grid-on-demand-data-loading-using-mustache-js/
Sorting a Grid using MustacheJs
http://www.techguides.in/enable-sorting-in-a-grid-bound-using-mustache-js/
short answer: YES
long answer: for security reasons [1], you need to wrap your JSON aray in an object anyways. for Mustache or any other library to be able to access your array you need to have at least one parent key on which you can base your iterator.
The "repo" key on your sample is the helper you need to tell mustache "go and iterate on the array that is inside the repo key", otherwise you have no way to tell the template what you want to output where
[1] this is just one of many resources you can find about why you need to wrap your JSON response in an object http://incompleteness.me/blog/2007/03/05/json-is-not-as-safe-as-people-think-it-is/

Resources