Currently I am pulling information from two JSON files stored online. My goal is to display the information stored within these files in my app, using one for content and the other for attributes that can apply to the content, like background and font color.
My main issue is this:
I am trying to fill an ObservableArray with other arrays, and then reference the information stored within each of those within the XML file. A fairly simple idea, yes?
Content JSON
{
"content": [
{
"description": "If you’ve been dreaming about owning a customizable smartwatch, the modular watch that London-based Blocks promised is now available ...",
"image": "https:\/\/cdn3.vox-cdn.com\/thumbor\/mOV6mjP_AI50YsQDbQ81444XEB4=\/0x21:2520x1701\/1310x873\/cdn0.vox-cdn.com\/uploads\/chorus_image\/image\/49811865\/hero-bg_2x.0.0.jpg",
"created_utc": "1467036570",
"title": "The Blocks modular smartwatch can now be pre-ordered",
"type": "04",
"url": "http:\/\/www.theverge.com\/circuitbreaker\/2016\/6\/9\/11894152\/blocks-modular-smartwatch-pre-order"
},
{
"description": "At Lenovo TechWorld, we got a glimpse at the Moto Z's developer mod kit and how it can be used to make wacky and weird slip-on attachments.",
"image": "http://img.youtube.com/vi/A0YFmMEjXP0/mqdefault.jpg",
"created_utc": "1467032545",
"title": "Lenovo's Experimental Moto Mods",
"feedid": "03",
"url": "https://www.youtube.com/watch?v=A0YFmMEjXP0"
},
{
"description": "",
"image": "https://pbs.twimg.com/media/CkmZk8QXIAEKnTF.jpg",
"created_utc": "1467035885",
"title": "The US just approved six airlines to begin flying to Cuba",
"feedid": "02",
"url": "http://www.theverge.com/2016/6/10/11903034/us-cuba-airlines-american-southwest-frontier-jetblue"
},
{
"description": "'Texts from Hillary' photo raised questions about Clinton email habits at State Department",
"image": "https://cdn1.vox-cdn.com/thumbor/COJRCv7KVVwj3uO5qt1XHZ5F02Y=/0x82:3010x2089/1280x854/cdn0.vox-cdn.com/uploads/chorus_image/image/49821307/AP_16147060028688.0.0.jpg",
"created_utc": "1467036728",
"title": "The photo went viral enough to catch the eye of the State Department.",
"feedid": "01",
"url": "https://www.facebook.com/verge/posts/1116679778368364"
},
{
"description": "One of the benefits of being (somewhat) bilingual is you get double the internet content. I feel very blessed to be able to enjoy both American internet full of...",
"image": "https://cdn2.vox-cdn.com/thumbor/gM8KeNQUzto6fmdot7wfA_q9jSs=/0x0:3000x2000/1310x873/cdn0.vox-cdn.com/uploads/chorus_image/image/49820235/GettyImages-499350590.0.jpg",
"created_utc": "1467036669",
"title": "If you drop an ant from the top of the Empire State Building, will it die?",
"feedid": "04",
"url": "http://www.theverge.com/tldr/2016/6/10/11894028/ant-dropped-from-empire-state-building-science-experiment"
},
{
"description": "Tesla has denied that its cars suffer from suspension defects, suggesting that comments from the US National Highway Traffic Safety Administration (NHTSA) have been misinterpreted.",
"image": "https://cdn2.vox-cdn.com/thumbor/IAh-NZAZzH_AwdO2ubVMKlZkB2Y=/187x0:2212x1350/1310x873/cdn0.vox-cdn.com/uploads/chorus_image/image/49819011/model-s-photo-gallery-06.0.0.jpg",
"created_utc": "1467042890",
"title": "Tesla denies Model S suspension defects, chides journalist in blog post",
"feedid": "04",
"url": "http://www.theverge.com/circuitbreaker/2016/6/9/11894152/blocks-modular-smartwatch-pre-order"
}
]
}
Sources and Attributes JSON
{
"sources": [
{
"category":"news",
"subject":"technology",
"adsenabled":true,
"bannerimgsrc":"https://www.camplaurel.com/images/pagegraphics/home/l-header-bg.jpg",
"rowbgimgsrc":"https://www.camplaurel.com/images/pagegraphics/home/l-header-bg.jpg",
"titlebgcolor":"#ffffff",
"row2ndcolor":"#000000",
"rowtxtcolor":"#e22805",
"rowbgcolor":"#ffffff",
"iconsrc": "https://pbs.twimg.com/profile_images/615501837341466624/I4jVBBp-.jpg",
"id": 1,
"shortname": "verge",
"name": "The Verge"
},
{
"category":"news",
"subject":"leisure",
"adsenabled":true,
"bannerimgsrc":"https://pbs.twimg.com/profile_banners/275686563/1433249898/1500x500",
"rowbgimgsrc":"null",
"titlebgcolor":"#ece4d1",
"row2ndcolor":"#9b4e34",
"rowtxtcolor":"#6b2e1e",
"rowbgcolor":"#ece4d1",
"iconsrc": "https://camo.githubusercontent.com/b13830f5a9baecd3d83ef5cae4d5107d25cdbfbe/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f3732313033382f313732383830352f35336532613364382d363262352d313165332d383964312d3934376632373062646430332e706e67",
"id": 1,
"shortname": "Laurel South",
"name": "Camp Laurel South, Mains Premier Sleep Over Camp"
}
]
,
"feeds": [
{
"hidden": false,
"iconsrc": "http://icons.iconarchive.com/icons/danleech/simple/1024/facebook-icon.png",
"id": 1,
"notistat": "Sound and Text",
"sourceid":1,
"title": "The Verge Facebook"
},
{
"hidden": false,
"iconsrc": "http://icons.iconarchive.com/icons/danleech/simple/1024/facebook-icon.png",
"id": 2,
"notistat": "Sound and Text",
"sourceid":1,
"title": "The Verge Twitter"
},
{
"hidden": false,
"iconsrc": "http://icons.iconarchive.com/icons/danleech/simple/1024/facebook-icon.png",
"id": 3,
"notistat": "Sound and Text",
"sourceid": 1,
"title": "The Verge Youtube"
},
{
"hidden": false,
"iconsrc": "http://icons.iconarchive.com/icons/danleech/simple/1024/facebook-icon.png",
"id": 4,
"notistat": "Sound and Text",
"sourceid": 1,
"title": "The Verge RSS"
}
]
}
My JavaScript file uses a variable listed as bindingContext as the bindingContext of the page. myArray is a part of the bindingContext, and is being pushed into by my JSON mapping and loading functions, at least in theory.
var Observable = require('data/observable').Observable;
var ObservableArray = require('data/observable-array').ObservableArray;
var http = require("http");
var moment = require('moment');
var frameModule = require('ui/frame');
var bindingContext = new Observable({
title: "Loading...",
myArray: new ObservableArray()
});
function pageLoaded(args) {
var page = args.object;
page.bindingContext = bindingContext;
loadSources();
loadFeeds();
loadContent();
}
function loadContent() {
var content = [];
http.getJSON("http://www.doesntmatter.com/jsoncontent.php")
.then(function (r) {
bindingContext.title = 'Notifications Up to Date';
r.content.map( function(item) {
item.friendlyTime = moment(item.created_utc * 1000).fromNow();
content.push(item);
});
bindingContext.myArray.push(content);
console.log("content loaded.");
});
}
function loadSources() {
var mysources = [];
http.getJSON("http://www.secrets.com/jsonsource.php")
.then(function (r) {
r.sources.map( function(item) {
mysources.push(item);
console.log(item.name);
});
});
bindingContext.myArray.push(mysources);
console.log("sources loaded!");
};
}
//LoadSources should add all listed Sources into an array of sources, which is then pushed into the larger "myArray" which allows coloration and other css items to be determined for each object within an array
function loadFeeds() {
var myfeeds = [];
http.getJSON("http://www.shhhhhhhh.com/jsonsource.php")
.then(function (r) {
r.feeds.map( function(item) {
myfeeds.push(item);
});
bindingContext.myArray.push(myfeeds);
console.log("feeds loaded.");
});
}
//LoadFeeds should add all listed feeds into an array of feeds, which is also loaded into "myArray", which can then be drawn from to create individual color schemes
exports.pageLoaded = pageLoaded;
The part I am having a lot of trouble with is correctly referencing the array, subarrays, and contents of each within both the JavaScript file and the XML file due to a somewhat rusty knowledge of both languages.
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
<Page.actionBar>
<ActionBar title="Notify">
</ActionBar>
</Page.actionBar>
<ListView items="{{ myArray }}" itemTap="itemTap" loadMoreItems="loadMoreItems" class="containter">
<ListView.itemTemplate>
<GridLayout rows="21,*,*" columns="90,*" width="*" height="*" >
<!-- <Image row="0" col="0" colSpan="1" rowspan="3" src="{{ getItem[2].image }}" /> -->
<!-- <Label row="0" col="1" colSpan="1" class="time" text="{{ friendlyTime }}" textAlignment="right" /> -->
<!-- <Label row="1" col="1" colSpan="1" class="title" text="{{ content.title }}" margin="1" textWrap="true" /> -->
<!-- <Label row="2" col="1" colSpan="1" class="description" text="{{ description }}" textWrap="true" backgroundColor="{{ this is where I would want to reference the contents of the subarrays}}" /> -->
</GridLayout>
</ListView.itemTemplate>
</ListView>
</Page>
Again, just to reiterate: I have an ObservableArray which is part of the bindingContext of the page. This is being filled with other arrays, which are each filled with information I want to apply to my XML file. How can I reference this information using the correct syntax for both JavaScript and XML?
I think you actually need to rethink your design. ;-)
First issue that occurred to me is that myArray[0] can end up being content, sources or feeds. Just because you ran the code:
loadSources();
loadFeeds();
loadContent();
In a synchronous fashion, does not guarentee the result order; each one of those loads the file from a ASYNC source (i.e. in this case http); depending on which one of those ASYNC sources actually responds with its data first, it is which one will get put into your MyArray first. ;-)
Your second issue is that
<ListView items="{{ myArray }}"
Will only create three of your GridLayout templates; because their are only three myArray items (i.e the content, feeds, source) based on your data; I'm pretty sure you aren't just wanting to show three line items.
Now the question becomes do you need each item to link to a source to a feed, or do you just want to combine all three types and display each type of line item differently based on which type it it.
Related
I am trying to create a status list from two separate JSON sources. The list will display general info from the first source, and show a status color based on the number of people in the second source.
The first source contains general data that will not be changing much (i.e. feed name, version, description) and likely called only two times a day. See code example below:
/metadata
{
data: [
{
"feedName": "Feed 1",
"version": "000001",
"location": "1234 Main Street, New York, New York"
"description": "This feed gives information on the number of people in Building A at a given time."
},
{
"feedName": "Feed 2",
"version": "000001",
"location": "1000 Broad Street, New York, New York"
"description": "This feed gives information on the number of people in Building B at a given time."
},
{
"feedName": "Feed 3",
"version": "000001",
"location": "1111 Governor Street, New York, New York"
"description": "This feed gives information on the number of people in Building C at a given time."
}
]
}
The second source contains data on each feed that will change very often. This source will be called more frequently; about every hour.
/customers
{
data: [
{
"metricName": "Feed 1",
"customerNumber": "10",
"time": "2012-10-03 15:30:00"
},
{
"metricName": "Feed 2",
"customerNumber": "5",
"time": "2012-10-03 15:30:00"
},
{
"metricName": "Feed 3",
"customerNumber": "15",
"time": "2012-10-03 15:30:00"
}
]
}
Where metricName and feedName are actually the same values.
I've only dealt with one JSON source per list before, where my Javascript would look like this:
$scope.metadataList = function(){
$http.get('/metadata')
.then(function(result) {
$scope.metadata = result.data.data;
});
}
and corresponding HTML would look like this:
<ul ng-repeat = "data in metadata | orderBy: ['feedName']">
<li> {{data.feedName}}, {{data.version}} </li>
</ul>
So my question is, how to I make async calls to each data source? How do I match them up to populate my list with both the metadata information and the customer information?
Update
Before anyone asks, I did try ng-repeat = "data in metadata.concat(customers)" where "customers" defines the second data source, (as shown in Ng-repeat datas from 2 json Angular) but that only appends to the end of the list ... not quite what I was going for.
Thank you in advance.
First, you can call the all() method from the $q service to resolve multiple promises, in that case the two requests.
// both promises calling your api to get the jsons
var promises = {
metadataPromise: $http.get('/echo/json/', {}),
customersPromise: $http.get('/echo/json/', {})
};
$q.all(promises).then(function(response) {
metadata = response.metadataPromise;
customers = response.customersPromise;
joinMetadataAndCustomers();
}, function(response) {
// in case any promise is rejected
});
After that, you check for every feedName the metricName which matches it using filter. In the end, you can merge both with angular.merge.
var joinMetadataAndCustomers = function() {
metadata.data.forEach(function(mtd) {
customers.data.filter(function(customer) {
return customer.metricName === mtd.feedName;
}).forEach(function(customer) {
$ctrl.metadataAndCustomers.push(angular.merge({}, mtd, customer));
});
});
}
Not sure if it's the best approach, but it works. Of course can be improved according to your needs. For example, if you only have one single match, the last forEach can be avoided.
Fiddle with an example: https://jsfiddle.net/virgilioafonsojr/tv1ujet0/
I hope it helps.
I'm using this code to specify what data to take and how to add it into my HTML.
window.onload = (function(CMS) {
//parse your csv file
Papa.parse("LINK", {
download: true,
complete: function(results) {
console.log(results);
$.each(results.data.slice(1), // skip first row of CSV headings
function(find, data) {
var title = data[0];
var link = data[4];
var date = data[2];
var type = data[3];
$('ul.nflist').append($('<li>', {
html: '' + title + ' ' + ' ' + '<span class="category">' + type + '</span>'
}));
});
//weird issue with an empty line.. just delete the last <li>
$('ul.nflist li:last-child').remove();
//Now that your data is clean and in its proper place you can begin to do the preety stuff like add images to corresponding categories
//First hide the category tag...
$(".category").hide();
// Now lets search for categories and add images
$('ul.nflist li:contains("sm")').prepend('<img src="http://www.jonar.com/portal/partner/img/sendemailo.png" />');
$('ul.nflist li:contains("blog")').prepend('<img src="http://www.jonar.com/portal/partner/img/bello.png" />');
$('ul.nflist li:contains("ann")').prepend('<img src="http://www.jonar.com/portal/partner/img/calendaro.png" />');
$('ul.nflist li:contains("itp")').prepend('<img src="http://www.jonar.com/portal/partner/img/pluscircleo.png" />');
}
});
});
The json file looks like this when the csv is parsed:
[
{
"title": "Choice, Happiness and Spaghetti Sauce",
"summary_text": "Delivering product variety: chunky spaghetti sauce, zesty pickles, or weak coffee? Gladwell explains how the root of happy customers is product variety.",
"date": "30-Jan-13",
"type": "sm",
"link": "https://www.facebook.com/permalink.php?id=380939405308665&story_fbid=298838986905013"
},
{
"title": "Servoy Interviewed Us",
"summary_text": "Servoy interviewed our managing director,Jon Ruby. Find out why we chose Servoy and learn about our development best practices.",
"date": "4-Nov-14",
"type": "itp",
"link": "https://plus.google.com/+ServoyPlus/posts/aUL28cD2hfH"
},
{
"title": "Come Together, Right Now: The Benefits of Cross-Functional Teams",
"summary_text": "What do you get when you put an engineer, a doctor and a lawyer in one room? Find out how to create an environment to sustain cross-functional teams.",
"date": "2-May-13",
"type": "blog",
"link": "http://www.jonar.com/jonarblog/come-together-right-now-the-benefits-of-cross-functional-teams/"
},
{
"title": "What is ERP?",
"summary_text": "The acronym, �ERP� is tossed around constantly, but what does it actually mean for your business?",
"date": "25-Aug-11",
"type": "sm",
"link": "https://www.youtube.com/watch?v=PVRgIXLWDHs"
},
{
"title": "Admit You Don�t Know � Take The Road Less Traveled",
"summary_text": "If you�ve ever felt like a fraud, you�re not alone. Instead of ignoring it, here�s why you should embrace the experience of Imposter Syndrome.",
"date": "17-Oct-14",
"type": "blog",
"link": "http://www.jonar.com/jonarblog/admit-you-dont-know-take-the-road-less-travelled/"
},
{
"title": "Jonar is Looking to Build Our Network of VAP�s",
"summary_text": "Jonar has started building an international network of partners. Want in? Join us on our journey to reinvent ERP.",
"date": "no date",
"type": "ann",
"link": "http://www.jonar.com/new/signUp.html"
},
{
"title": ""
}
]
Here is the issue there are types that have sm. I don't want these rows... Lets say the type sm it should not include the row.. How can i filter the data?
Use this
$.each(results.data.slice(1), // skip first row of CSV headings
function(find, data) {
if(data.type !="sm") {
var title = data.title;
var link = data.link;
var date = data.date;
var type = data.type;
}
}
);
Each element of the array is an object so you need to access the properties of that object:
Change :
var title = data[0];
To:
var title = data.title;
And do same for all other variables and properties
I am trying to follow this example on how to setup a combo-box using dojo, but wondering how one can specify name and value programmatically. The example presented uses the same values for label and value - which is probably not one wants in most cases.
{
"identifier": "abbreviation",
"label": "name",
"items": [
{ "abbreviation": "AL", "name": "Alabama" },
... other 48 states here ...
{ "abbreviation": "WY", "name": "Wyoming" }
]
}
If you are asking how to replace the hard coded list in the example then here is what you have to do. In the above scenario items was used to specify the data which is an array (abbreviations and names) of values.
In your case you will need to get the data / object from your data source. Once you have that data/object expose it to the view. Once this has been done you can now do the following structure.
You store is really your items above however stateStore will be a java script array which contains the data from your data source.
stateStore = [{"abbreviation": "AL", "name": "Alabama"},
... other 48 states here ...,
{ "abbreviation": "WY", "name": "Wyoming" }]
// create FilteringSelect widget, populating its options from the store
var select = new dijit.form.FilteringSelect({
name: "stateSelect",
placeHolder: "Select a State",
store: stateStore
}, "stateSelect");
HTML
<div style="width:50%;float: left;">
<h1>dijit.form.Select</h1>
<label for="stateSelect">State:</label>
<div id="stateSelect"></div>
</div>
I'm working on an application that lets our security dispatchers update a page that contains current road and campus conditions. The backend is a nodejs/express stack with and the data is a simple JSON structure that looks something like this:
{
"campus": {"condition": "open", "status": "normal"},
"roads": {"condition": "wet", "status": "alert"},
"adjacentroads": {"condition": "not applicable", "status": "warning"},
"transit": {"condition": "on schedule", "status": "normal"},
"classes": {"condition": "on schedule", "status": "normal"},
"exams": {"condition": "on schedule", "status": "normal"},
"announcements" : "The campus is currently under attack by a herd of wild velociraptors. It is recommended that you do not come to campus at this time. Busses are delayed.",
"sidebar": [
"<p>Constant traffic updates can be heard on radio station AM1234. Traffic updates also run every 10 minutes on AM5678 and AM901.</p>",
"<p>This report is also available at <strong>555-555-1234</strong> and will be updated whenever conditions change.</p>"
],
"links": [
{
"category": "Transportation Links",
"links": [
{
"url": "http://www.localtransit.whatever",
"text" : "Local Transit Agency"
},
{
"url": "http://m.localtransit.whatever",
"text" : "Local Transit Agency Mobile Site"
}
]
},
{
"category": "Weather Forecasts",
"links": [
{
"url": "http://weatheroffice.ec.gc.ca/canada_e.",
"text" : "Environment Canada"
},
{
"url": "http://www.theweathernetwork.com",
"text" : "The Weather Network"
}
]
},
{
"category": "Campus Notices & Conditions",
"links": [
{
"url": "http://www.foo.bar/security",
"text" : "Security Alerts & Traffic Notices"
},
{
"url": "http://foo.bar/athletics/whatever",
"text" : "Recreation & Athletics Conditions"
}
]
},
{
"category": "Wildlife Links",
"links": [
{
"url": "http://velociraptors.info",
"text" : "Velociraptor Encounters"
}
]
}
],
"lastupdated": 1333151930179
}
I'm wondering what the best way of working with this data on the client side would be (e.g. on the page that the dispatchers use to update the data). The page is a mix of selects (the campus, roads, etc conditions), TinyMCE textareas (announcements and sidebar) and text inputs (links). I'm open to changing this data structure if necessary but it seems to me to work well. I've been looking at Backbone, and also Can.JS but I'm not sure if either of those are suitable for this.
Some additional information:
there's no need to update an individual item in the data structure separatly; I plan on POSTing the entire structure when it's saved. That said...
there's actually two different views, one for the dispatchers and another for their supervisors. The dispatchers only have the ability to change the campus, roads, etc conditions through drop-downs and furthermore can only change the "condition" key; each possible condition has a default status assigned to it. Supervisors can override the default status, and have access to the announcements, sidebar and links keys. Maybe I do need to rethink the previous point about POSTing the whole thing at once?
the supervisors need to be able to add and remove links, as well as add and remove entire link categories. This means that DOM elements need to be added and removed, which is why I'm thinking of using something like Backbone or Can.js instead of just writing some ghetto solution that looks at all the form elements and builds the appropriate JSON to POST to the server.
Suggestions welcomed!
CanJS works great with nested data. can.Model is inheriting can.Observe which allows you to listen to any changes in the object structure.
If you include can.Observe.Delegate you have even more powerful event mechanism (example from the docs):
// create an observable
var observe = new can.Observe({
name : {
first : "Justin Meyer"
}
})
var handler;
//listen to changes on a property
observe.delegate("name.first","set",
handler = function(ev, newVal, oldVal, prop){
this //-> "Justin"
ev.currentTarget //-> observe
newVal //-> "Justin Meyer"
oldVal //-> "Justin"
prop //-> "name.first"
});
// change the property
observe.attr('name.first',"Justin")
I have this code:
var attachmentsModel = {
convAttachments: ko.mapping.fromJS([])
};
$(function() {
ko.applyBindings(attachmentsModel)
refreshConvAttachments();
});
function refreshConvAttachments() {
$.ajax({
url: '/xxxxxxx/',
success: function (dataJS) {
// Send KO the data
ko.mapping.updateFromJS(attachmentsModel.convAttachments, dataJS);
}
});
}
The AJAX call above returns:
[{
"title": "BillGates",
"added_by": "xxx",
"thumb": "urlhere",
"id": 410,
"link": "/link/410",
"added_on": "2011-02-22T12:57:09-08:00"
}, {
"title": "biz-stone",
"added_by": "xxx",
"urlhere",
"id": 411,
"link": "/link/411",
"added_on": "2011-02-22T12:57:53-08:00"
}]
This works fine. Later though the user is able to add an attachment, and that's where it's breaking. While it adds the new attachment to the mode, and displays on the page, it removes all the previously loaded items in the attachmentsModel.convAttachments.
Later on, this happens:
ko.mapping.updateFromJS(attachmentsModel.convAttachments, file);
Ajax Returns:
[{
"title": "eric_schmidt",
"added_by": "xxx",
"thumb": "xxxxxx",
"id": 417,
"link": "/link/417",
"added_on": "2011-02-22T13:16:45-08:00"
}]
I hope that gives a clear walk through, if not please let me know. Any ideas why knockoutjs is kill everything when I use updateFromJS?
ko.mapping.updateFromJS() expects that you are receiving the complete list of items that was originally prepared with ko.mapping.fromJS(). Any items that are missing from the original are considered to be deleted and any new items in the updates are considered additions. So, currently the mapping plugin will not allow you to do incremental updates in this way.
If you are doing incremental updates, your best bet would be to locate the items that you need to update and either replace them completely or replace individual observables on each item.
you could always try using
$.extend(attachmentsModel.convAttachments,ko.mapping.fromJS(dataJS));
Although i am not quite sure if that will update all the bindings properly, you might have to reply the binding by calling
ko.applyBindings(attachmentsModel)