Parse: JavaScript Promises issue - javascript

I am trying to wrap my head around Promises, then , when, and everything else that goes along with it. I am not having much success. Here is what I'm trying to accomplish in English, and maybe somebody can crack the code because so far nothing I've written works.
I am writing a SPA (single page app) for mobile devices. Essentially all the content is is one giant HTML page with a bunch of DIV's. However, only one DIV is shown at a time. The user will have a tab bar to click on each of the icons to show/hide DIV's. Think of something like the Apple App Store interface with "Featured", "Top Charts", "Explore", "Search", and "Updates" at the bottom.
Parse database query of table Businesses for 1 business with AppUrl=example.com
Resulting business objectId is used to query table Navigation for all pieces of the navigation. Things like "Home", "About Us", "Menus", "Events", "Contact", etc.
Resulting navigation items are looped to render DIV's with content in them. The content comes from the tables below depending on the Module column:
"Home" = Photos table
"About Us" = Pages table
"Menus" = Lists table
"Event" = Lists table
That's basically it. Pretty simple, but obviously there are nest queries within #4. I don't know if I should be creating one giant object in my queries and then outputting that? Or creating a bunch of different objects with arrays inside of them? Really kind of lost since this style of syntax is different than say PHP. Advice?
Here is my non-database connected version:
app.get('/', function(req, res){
var frontpageImages = [
{ caption:"Eggplant, Prosciutto, and Pesto Pressed Sandwiches.", file:"image01.jpg", position:"15%" },
{ caption:"Pico de Gallo", file:"image02.jpg", position:"75%" },
{ caption:"B.L.A.T Croque Madame", file:"image03.jpg", position:"20%" },
{ caption:"Double Oreo Brownie Cupcake", file:"image04.jpg", position:"80%" },
{ caption:"Baked Chicken Chimichangas with Monterey Jack Cheese Sauce", file:"image05.jpg", position:"20%" }
]
var menu = [
{ divider:"Appetizers" },
{ name:"French Fries", picture:"menu-french-fries", subname:"$4.95" },
{ name:"Loaded Cheese Fries", picture:"menu-cheese-fries", subname:"$7.95" },
{ name:"Gaelic Chips", picture:"menu-gaelic-chips", subname:"$2.95" },
{ name:"Jalapeno Mac n' Cheese", picture:"menu-jalapeno-mac-n-cheese", subname:"$4.95" },
{ name:"Chicken Wings", picture:"menu-chicken-wings", subname:"$8.50" },
{ name:"Irish Nachos", picture:"menu-irish-nachos", subname:"$8.50" },
{ name:"Black & Tan Onion Rings", picture:"menu-onion-rings", subname:"$6.95" },
{ name:"Mac's Quesadillas", picture:"menu-quesadillas", subname:"$8.50" },
{ name:"Banger Bites", picture:"menu-banger-bites", subname:"$7.95" },
{ divider:"Salads" },
{ name:"Caesar Salad", picture:"menu-caesar-salad", subname:"$6.50" },
{ name:"House Salad", picture:"menu-house-salad", subname:"$6.50" },
{ name:"Buffalo Chicken Salad (Grilled or Battered)", picture:"menu-buffalo-chicken-salad", subname:"$8.95" },
{ divider:"Sandwiches & Burgers" },
{ name:"Rueben", picture:"menu-reuben", subname:"$8.50" },
{ name:"Dublin Corned Beef", picture:"menu-corned-beef-sandwich", subname:"$8.50" },
{ name:"Philly Cheese Steak", picture:"menu-philly-cheese-steak", subname:"$8.50" },
{ name:"Grilled Chicken", picture:"menu-grilled-chicken-sandwich", subname:"$8.50" },
{ name:"Club Sandwich", picture:"menu-club-sandwich", subname:"$8.50" },
{ name:"Not-So-Irish Burger", picture:"menu-irish-burger", subname:"$9.95" },
{ name:"Dirty Burger", picture:"menu-dirty-burger", subname:"$7.95" },
{ name:"Aurora Burger", picture:"menu-aurora-burger", subname:"$10.95" },
{ name:"Bleu Cheese Burger", picture:"menu-bleu-cheese-burger", subname:"$11.95" },
{ name:"Additional Burger Toppings", picture:"menu-burger-toppings", subname:"$0.50" },
{ divider:"Irish Favorites & Entrees" },
{ name:"Beer Battered Fish N' Chips", picture:"menu-fish-and-chips", subname:"$11.50" },
{ name:"Bangers And Mash", picture:"menu-bangers-and-mash", subname:"$10.95" },
{ name:"Shepherd's Pie", picture:"menu-shepherds-pie", subname:"$10.95" },
{ divider:"Brunch" },
{ name:"Irish Breakfast", picture:"menu-irish-breakfast", subname:"$11.50" },
{ name:"American Breakfast", picture:"menu-american-breakfast", subname:"$11.50" },
{ name:"Irish Breakfast Roll", picture:"menu-irish-breakfast-roll", subname:"$8.95" },
{ name:"English Muffin, Scrambled Eggs, Cheddar and Irish Rasher", picture:"menu-irish-rasher", subname:"$7.50" },
{ name:"3 Egg Omelette", picture:"menu-omelette", subname:"$6.50" },
{ name:"Eggs Benedict", picture:"menu-eggs-benedict", subname:"$8.50" },
{ name:"3 Pancakes with Maple Syrup", picture:"menu-pancakes", subname:"$6.00" },
{ name:"Grilled Turkey and Swiss", picture:"menu-grilled-turkey-and-swiss", subname:"$7.00" }
];
var drinks = [
{ name: "Bahama Bomb", desc: "Bacardi 151 Rum, Cruzan Coconut Rum, Creme de Banana, Pineapple juice, and Sprite.", subname: "$9.95" },
{ name: "Tropical Margarita", desc: "Grand Marnier, Cruzan Coconut Rum, Blue Curacao, sour mix, and orange juice. Garnished with lemon, lime, and cherry.", subname: "$10.95" },
{ name: "LOL[emonade]", desc: "Absolute Citron, Triple Sec, muddled lemon and simple syrup, sour mix, and Sprite.", subname: "$9.95" }
];
var events = [
{ divider:"Upcoming Events" },
{ name: "Super Bowl Party", subname: "1/28" },
{ name: "Valentine's Singles Party", subname: "2/14" },
{ divider:"Weekly Events" },
{ name: "Hospitality Night", subname: "Monday" },
{ name: "Trivia Night", subname: "Tuesday" },
{ name: "Karaoke with Liam", subname: "Thursday" }
];
res.render('index', {
nav:[
{ name:"Home", title:"Clark's Bar and Grille", url:"home", icon:"home", module:"home", run:"startSlider", source:frontpageImages },
{ name:"Menu", url:"menu", icon:"cutlery", module:"list", source:menu },
{ name:"Drinks", url:"drinks", icon:"glass", module:"list", source:drinks },
{ name:"Events", url:"events", icon:"calendar", module:"list", source:events },
{ name:"Restaurant Info", title:"Restaurant Info", url:"business-info", icon:"info-circle", module:"business-info" },
{ name:"Instagram Feed", title:"Instagram", url:"instagram", icon:"instagram", module:"instagram", run:"startInstagram" },
{ name:"Like and Follow Us", title:"Social Media", url:"social-media", icon:"thumbs-up", module:"social-media-links" },
{ name:"Contact Clark's", title:"Contact Clark's", url:"contact", icon:"envelope", module:"contact" }
]
});
});
When the page renders now, I have the index.ejs loop the nav object and display each DIV (Home, Menu, Drinks, Events, etc). Each array within the nav object has a key called source which returns the objects for them listed above. The page renders perfectly, it's just not connected to a database. I would like to swap all that out with a DB connected version!

I hope this code will help you, that's the best I can suggest with what you provided:
function handleError(message, error) {
//Handle any error here, for example:
console.error(message, error);
res.send(500, message);
}
var responseContent = {
nav: [],
};
getBusiness(); //start fetching data
function getBusiness() {
var businessQuery = /*query to get element AppUrl=example.com*/;
businessQuery.first().then(
getNavigation,
handleError.bind(null, 'error getting business'));
}
function getNavigations(business) {
var navigationsQuery = /*query to get navigation elements*/;
var promises = [];
navigationsQuery.each(function (navigation) {
promises.push(processNavigation(navigation));
}).then(
function () {
Parse.Promise.when(promises).then(
renderResult,
handleError.bind(null, 'error processing navigations'));
},
handleError.bind(null, 'error iterating navigations'));
}
function processNavigation(navigation) {
var promise = Parse.Promise();
var nav = {
name: /*name*/,
url: /*url*/,
};
responseContent.nav.push(nav);
switch (/*module*/) {
case 'Home':
getPhotosContent(/*args*/).then(
function (source) {
nav.source = source;
promise.resolve();
},
function (error) {
promise.reject(error);
}
);
break;
//can do similar code for 'About Us', 'Menus', ...
default:
promise.resolve();
}
return promise;
}
function getPhotosContent(/*args*/) {
var promise = Parse.Promise();
var results = [];
var photosQuery = /*query to get photos*/;
photosQuery.each(function (photo) {
results.push(photo);
}).then(
function () {
promise.resolve(results);
}, function (error) {
promise.reject(error);
}
);
return promise;
}
function renderResult() {
res.render('index', responseContent);
}

Related

How to create a List Render JSON from a Dynamic List for an API response in Vue?

I am a beginner in at Vue.js version 2.6.11.
I have a form where a person can add a list of toys. So the list is dynamic. How do we add this dynamic list into a JSON data structure in a POST request?
I cannot change the API.
For example the first list to send to a POST request might be
"toyCollection":
[
{
"toyName": "yo-yo",
"toyDescription": "ball on a string",
"toyAge": 15,
"company": {
"companyName": "yo yo company"
"companyYear": "1999"
}
}
]
The second time someone creates a list of toys in this dynamic list might be
"toyCollection":
[
{
"toyName": "yo-yo",
"toyDescription": "ball on a string",
"toyAge": 15,
"company": {
"companyName": "yo yo company"
"companyYear": "1999"
}
},
{
"toyName": "barbie",
"toyDescription": "dolls in a house",
"toyAge": 21,
"company": {
"companyName": "mattel"
"companyYear": "1959"
}
},
{
"toyName": "transformers",
"toyDescription": "robots in disguise",
"toyAge": 20,
"company": {
"companyName": "Hasbro"
"companyYear": "1984"
}
}
]
How do we write this in Vue so that this is dynamic?
methods: {
const postRequest = {
toyCollection: [ //if 1 toy in list
{
toyName: "yo-yo", // this.form.toyName <---- would read the data
toyDescription: "ball on a string", //hardcoded here for simplicity for example
toyAge: 15,
company: {
companyName: "yo yo company"
similarToysFromCompany: "1999"
}
}
]
}
}
If there are three toys in the collection
methods: {
const postRequest = {
toyCollection: [ //if 3 toys in list
{
toyName: "yo-yo",
toyDescription: "ball on a string",
toyAge: 15,
company: {
companyName: "yo yo company"
similarToysFromCompany: "1999"
}
},
{
toyName: "barbie",
toyDescription: "dolls in a house",
toyAge: 21,
company: {
companyName: "mattel"
companyYear: "1959"
}
},
{
toyName: "transformers",
toyDescription: "robots in disguise",
toyAge: 20,
company: {
companyName: "Hasbro"
companyYear: "1984"
}
}
]
}
}
The list can be any size, depending on how many toys a person adds to this list.
How do we make this dynamic based on the list?
Then I would call my API with this object
this.methodCallToAPI(postRequest);
Thanks for any help!
==============
EDIT
I have a template to input fields
<form>
<!-- Name -->
<input
v-model="form.toyName"
id="toy-name"
class="input"
type="text"
/>
</div>
</form>
Then in the Script, it watches or updates the data fields based on what the user types into the input text fields.
export default {
name: "CreateToyCollection",
data () {
return {
form: {
toyName: "",
toyDescription: "",
toyAge: "",
company: {
companyName: "",
similarToysFromCompany: ""
}
}
}
},
watch: {
this.form.toyName = "";
this.form.toyDescription = "";
this.form.toyAge = "";
// etc for Company
}
}
I'm working on the list part, but this is how I want to pass in the dynamic data
In the data add a new array toyCollection :
data () {
return {
toyCollection: [],
form: {
toyName: "",
...
},
...
Every time form is submitted, push the submitted data to it like this.toyCollection.push(data)
Later in your post request you can send this.toyCollection as the payload.

How can I format an excel file with empty rows to have nested arrays and match a JSON object that I need to render?

I am facing an issue with an excel file. I receive some data from the DB and the user should be able to replace that data with a spreadsheet that looks like this:
This is how the data comes from the DB and how the excel file should be finally formatted:
"employers": [{
"id": "4147199311345513",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}, {
"id": "3763171269270198",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}]
So I need to take that spreadsheet and format it to look like that JSON above. All of this with Javascript/React.
This is what I have so far to format my excel file and render it:
const [excelData, setExcelData] = useState({ rows: [], fileName: "" });
const fileHandler = (event) => {
let fileObj = event.target.files[0];
ExcelRenderer(fileObj, (err, resp) => {
if (err) {
console.log(err);
} else {
let newRows = [];
let shiftRows = [];
console.log(resp.rows);
resp.rows.slice(1).map((row, index) => {
if (row && row !== "undefined") {
return newRows.push({
key: index,
employer: {
name: row[0],
description: row[1],
employerUrl: row[2],
employerUrlText: row[3],
shifts: shiftRows.push({ shift: row[2] }),
},
});
}
return false;
});
setExcelData({ rows: newRows, fileName: fileObj.name });
}
});
};
That console.log above (console.log(resp.rows)) returns this:
Where the first row are the headers of the excel file.
And the code above ends up like this and it should be exactly as the JSON I mentioned:
rows: [
{
key: 0,
employer: {
name: 'AT&T',
description: 'AT&T is a world premier employer with a bunch of stuff here and there.',
shifts: 1
}
},
{
key: 1,
employer: {
shifts: 2
}
},
{
key: 2,
employer: {
shifts: 3
}
},
{
key: 3,
employer: {
shifts: 4
}
},
{
key: 4,
employer: {
name: 'Verizon',
description: 'Verizon is a world premier employer with a bunch of stuff here and there.',
shifts: 5
}
},
{
key: 5,
employer: {
shifts: 6
}
},
{
key: 6,
employer: {
shifts: 7
}
},
{
key: 7,
employer: {
shifts: 8
}
}
],
fileName: 'EmployerChats.xlsx',
false: {
rows: [
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/0/link.png',
description: 'This is some text'
},
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/1/link.png',
description: 'This is some text'
}
]
},
I am using this plugin to help me render the excel file: https://www.npmjs.com/package/react-excel-renderer
Any ideas on what can I do to make format the spreadsheet data as the JSON?
Please notice those empty rows.
For example every time there is a new employer name, that's a new row or item in the array, then all of the columns and rows below and after Shift Name is a new nested array of objects. Hence, this file contains an array with a length of 2 and then it contains another array of items when it hits the Shift Name column.
Is it clear?
1st of all - you don't need to follow 'original', class based setState. In FC you can just use two separate useState.
const [rows, setRows] = useState([]);
const [fileName, setFileName] = useState("");
Data conversion
I know that you need a bit different workflow, but this can be usefull (common point - data structure), too - as conversion guide, read on.
You don't need to use ExcelRenderer to operate on data from db and render it as sheet. Converted data can be exported to file later.
You can just create array of array (aoa) that follows expected view (rows = array of row cells array). To do this you need very easy algorithm:
let newData = []
map over emplyers, for each (emp):
set flag let first = true;
map over shifts, for each (shift):
if( first ) { newData.push( [emp.name, emp.descr, shift.name, shift.timezone...]); first = false;
} else newData.push( [null, null, shift.name, shift.timezone...]);
setRows( newData );
Rendering
<OutTable/> operates on data and colums props - structures similar to internal state. 'datais ourrows, we only needcolumns` prop, just another state value:
const [columns, setColumns] = useState([
{ name: "Employer name", key: 0 },
{ name: "Employer description", key: 1 },
{ name: "Shift name", key: 2 },
// ...
]);
and finally we can render it
return (
<OutTable data={rows] columns />
Later
User can operate on sheet view - f.e. insert rows using setRows() or download this as file (XLSX.writeFile()) after simple conversion:
var ws = XLSX.utils.aoa_to_sheet( columns.concat( rows ) );
There is a lot of utils you can use for conversions - see samples.
Back to your needs
We have data loaded from db, data in aoa form, rendered as sheet. I don't fully understand format you need, but for your db format conversion is simple (opposite to above) - you can follow it and adjust to your needs.
let newEmployers = [];
let empCounter = -1;
// itarate on rows, on each (`row`):
rows.map( (row) => {
// new employer
if( row[0] ) {
newEmployers.push( {
// id should be here
"employerName": row[0],
"employerDescription": row[1],
"shifts": [
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
]
} );
empCounter ++;
} else {
// new shift for current employer
newEmployers[empCounter].shifts.push(
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
);
}
});
// newEmployers can be sent to backend (as json) to update DB

AugularJS UI Router has element in dom but display blank

I'm building an app with Ionic + AngularJS, with a starter app.
It's basically tab view + side menu. Playground here.
So far I've achieved most of my goals, except for below weird actions:
When you click on the item from landing page, it goes to the view, view title changed successfully, but no content displayed. But if you inspect the element the content was there.
If you do a refresh on the blank page, it will jump back to landing page, then if you click the items on the landing page, it opens the blank page with content displayed.
There are two certain pages that have further questions, it is the blank page mentioned above and the next page when you click an item on the blank page. On these two pages when you do a refresh, it will jump back to landing page, why?
Also when I'm on these two pages, the bottom tab doesn't change it's active state, meaning you cannot navigate to home page by clicking home when you are on these two pages.
Piece of code here:
.state('app.cat', {
url: '/cat/:catname',
views: {
'menuContent': {
templateUrl: 'templates/category.html',
controller: 'CatCtrl'
}
}
})
.state('app.card', {
url: '/cat/:catname/:cardtitle',
views: {
'menuContent': {
templateUrl: 'templates/card.html',
controller: 'CardCtrl'
}
}
})
Looks a lot to ask but I've been stuck here for a while, if you could shed any lights on this that would be much appreciated.
I suggest you to create factory like this
.factory('Cards', function($q) {
// Might use a resource here that returns a JSON array
// Some fake testing data
var cards = [{
"categories": [{
"catid": "1",
"catname": "Test 1",
"catbanner":"//placehold.it/300x100?test-1",
"cards": [{
"id":"11","title": "Cat 1 Cards 1","cover":"img/list-1.jpg"
}, {
"id":"12","title": "Cat 1 Cards 2","cover":"img/list-2.jpg"
}]
}, {
"catid": "1",
"catname": "Test 2",
"catbanner":"//placehold.it/300x100?test-2",
"cards": [{
"id":"11","title": "Cat 1 Cards 1","cover":"11"
}, {
"id":"12","title": "Cat 1 Cards 1","cover":"12"
}]
}, {
"catid": "1",
"catname": "Test 3",
"catbanner":"//placehold.it/300x100?test-3",
"cards": [{
"id":"11","title": "Cat 1 Cards 1","cover":"11"
}, {
"id":"12","title": "Cat 1 Cards 1","cover":"12"
}]
}, {
"catid": "1",
"catname": "Test 4",
"catbanner":"//placehold.it/300x100?test-4",
"cards": [{
"id":"11","title": "Cat 1 Cards 1","cover":"11"
}, {
"id":"12","title": "Cat 1 Cards 1","cover":"12"
}]
}, {
"catid": "1",
"catname": "Test 5",
"catbanner":"//placehold.it/300x100?test-5",
"cards": [{
"id":"11","title": "Cat 1 Cards 1","cover":"11"
}, {
"id":"12","title": "Cat 1 Cards 1","cover":"12"
}]
}, {
"catid": "2",
"catname": "Test 6",
"catbanner":"//placehold.it/300x100?test-6",
"cards": [{
"id":"21","title": "Cat 1 Cards 1","cover":"21"
}]
}]
}];
var deferred = $q.defer();
var _cat = []
var _remove = function(card) { cards.splice(cards.indexOf(card), 1); }
var _getCat = function(catname) {
var array = [];
for (var i = 0; i < cards[0].categories.length; i++) {
if (cards[0].categories[i].catname === catname) {
array.push(cards[0].categories[i]);
}
}
angular.copy(array, _cat);
return deferred.promise;
}
var _getCard = function(catname, cardtitle) {
var array = [];
for (var i = 0; i < cards[0].categories.length; i++) {
if (cards[0].categories[i].catname === catname) {
for (var k = 0; i < cards[0].categories[i].cards.length; k++) {
if (cards[0].categories[i].cards[k].title === cardtitle) {
array.push(cards[0].categories[i].cards[k]);
}}
array.push(cards[0].categories[i]);
}
}
angular.copy(array, _cards);
return deferred.promise;
}
return {
all: function() { return cards; },
remove:_remove,
getCat:_getCat,
getCard:_getCard,
cat: _cat,
cards: _cards
};
});
and call methode who return promise like below
Cards.getCat($stateParams.catname).then(function () { $scope.cat = Cards.cat}, function () { alert("Error") });

Meteor + MongoDB: How to get nested data?

I'm new to Meteor and trying to figure out this issue I have.
I'm trying to load data from the Lessons collection based on the route being passed. e.g if /courses/level1/lesson1/1a is passed then show data
Unfortunately this doesn't work.
Am I on the right path or is there a better way of doing this?
Collection
{
"_id": "YSgr3fvjpEBn7ncRa",
"courseId": "level1",
"lesson": [
{
"lessonId": "lesson1",
"freeLesson": true,
"title": "Lesson 1",
"eachLesson": [
{
"eachLessonId": "1a",
"title": "This is (masculine)",
"video": "839843"
},
{
"eachLessonId": "1b",
"title": "That is (masculine)",
"video": "839843"
},
{
"eachLessonId": "1c",
"title": "This is (feminine)",
"video": "839843"
},
{
"eachLessonId": "1d",
"title": "That is (feminine)",
"video": "839843"
},
{
"eachLessonId": "1e",
"title": "Getting to know you",
"video": "839843"
}
]
}
]
}
Routes
Router.route("courses/:courseId/:lessonId/:eachLessonId", {
path:"/courses/:courseId/:lessonId/:eachLessonId",
layoutTemplate: "layoutLessons",
template:"lessons",
onBeforeAction:function(){
var currentUser = Meteor.userId();
if (currentUser) {
Session.set('courseId', this.params.courseId);
Session.set('lessonId', this.params.lessonId);
Session.set('eachLessonId', this.params.eachLessonId);
this.next();
} else {
Router.go('/')
}
},
});
Template helper
Template.lessons.onCreated(function(){
Meteor.subscribe('listLessons');
});
Template.lessons.helpers({
currentLesson: function() {
var currentLesson = Session.get('eachLessonId');
return Lessons.find({"lesson.eachLesson.eachLessonId" : currentLesson});
},
});
HTML
{{#each currentLesson}}
{{title}}
{{video}}
{{/each}}
Instead of storing courseId, lessonId and eachLessonId as Session values, you could use the Iron Router's waitOn and data option.
For example, you could rewrite your route as follows:
Router.route('/courses/:courseId/:lessonId/:eachLessonId', {
name: 'lessons',
layoutTemplate: 'layoutLessons',
template: 'lessons',
onBeforeAction: function() {
let currentUser = Meteor.user();
if (currentUser) this.next();
else Router.go('/');
},
data: function() {
var doc = Lessons.findOne({
"courseId": this.params.courseId,
"lesson.lessonId": this.params.lessonId,
"lesson.eachLesson.eachLessonId": this.params.eachLessonId
});
if (doc) {
var lesson = {};
var lessonId = this.params.eachLessonId;
_.each(doc.lesson, function(i) {
lesson = _.find(i.eachLesson, function(j) {
return j.eachLessonId == lessonId;
});
});
return lesson;
}
return {};
},
waitOn: function() {
return [
Meteor.subscribe('lesson', this.params.courseId, this.params.lessonId, this.params.eachLessonId)
];
}
});
This should set the data context to the requested eachLesson object. However, you may consider setting the data context to a document in the Lessons collection and then just picking certain eachLesson objects. In addition, you should create a publish function which returns just the requested Lessons document and not all of them, like you probably do now in your listLessons publication. You can pass all IDs as arguments to the corresponding publish function.

Reading json to create an array of objects with jQuery .each()

I'm trying to create an array of objects by reading in a json. This is the relevant code:
//president object consctructor
function president(a_presName, a_presDates, a_presNick, a_presImage) {
this.presName=a_presName;
this.presDates=a_presDates;
this.presNick=a_presNick;
this.presImage=a_presImage;
}
var myPres = new Array();
$(document).ready(function() {
$.getJSON('Presidents.json', function(data) {
$.each(data.presidents, function (i, item) {
myPres[i]=new president(item.presName, item.presDates, item.presNick, item.PresImage);
});
}); //end getJSON
document.write(myPres[1].presName);
}); //end doc ready
And this is the json:
{ "presidents": [ { "presName":"George Washington", "presDates":"1789-1797", "presNick":"Father of His Country", "presImage":"gwashington.gif" }, { "presName":"John Adams", "presDates":"1797-1801", "presNick":"Atlas of Independence", "presImage":"jadams.gif" }, { "presName":"Thomas Jefferson", "presDates":"1801-1809", "presNick":"Sage of Monticello", "presImage":"tjefferson.gif" }, { "presName":"James Madison", "presDates":"1809-1817", "presNick":"Father of the Constitution", "presImage":"jmadison.gif" }, { "presName":"James Monroe", "presDates":"1817-1825", "presNick":"Era-of-Good-Feeling President", "presImage":"jmonroe.gif" }, { "presName":"John Quincy Adams", "presDates":"1825-1829", "presNick":"Old Man Eloquent", "presImage":"jqadams.gif" }, { "presName":"Andrew Jackson", "presDates":"1829-1837", "presNick":"Old Hickory", "presImage":"ajackson.gif" }, { "presName":"Martin Van Buren", "presDates":"1837-1841", "presNick":"The Little Magician", "presImage":"mvanburen.gif" }, { "presName":"William Henry Harrison", "presDates":"1841", "presNick":"Old Tippecanoe", "presImage":"whharrison.gif" }, { "presName":"John Tyler", "presDates":"1841-1845", "presNick":"Accidental President", "presImage":"jtyler.gif" }, { "presName":"James Knox Polk", "presDates":"1845-1849", "presNick":"Young Hickory", "presImage":"jkpolk.gif" }, { "presName":"Zachary Taylor", "presDates":"1849-1850", "presNick":"Old Rough and Ready", "presImage":"ztaylor.gif" }, { "presName":"Millard Fillmore", "presDates":"1850-1853", "presNick":"The American Louis Philippe", "presImage":"mfillmore.gif" }, { "presName":"Franklin Pierce", "presDates":"1853-1857", "presNick":"Young Hickory of the Granite Hills", "presImage":"fpierce.gif" }, { "presName":"James Buchanan", "presDates":"1857-1861", "presNick":"Old Buck", "presImage":"jbuchanan.gif" }, { "presName":"Abraham Lincoln", "presDates":"1861-1865", "presNick":"Honest Abe", "presImage":"alincoln.gif" }, { "presName":"Andrew Johnson", "presDates":"1865-1869", "presNick":"None", "presImage":"ajohnson.gif" }, { "presName":"Ulysses Simpson Grant", "presDates":"1869-1877", "presNick":"Hero of Appomattox", "presImage":"usgrant.gif" }, { "presName":"Rutherford Birchard Hayes", "presDates":"1877-1881", "presNick":"Dark-Horse President", "presImage":"rbhayes.gif" }, { "presName":"James Abram Garfield", "presDates":"1881", "presNick":"None", "presImage":"jagarfield.gif" }, { "presName":"Chester Alan Arthur", "presDates":"1881-1885", "presNick":"The Gentleman Boss", "presImage":"caarthur.gif" }, { "presName":"Grover Cleveland", "presDates":"1885-1889", "presNick":"None", "presImage":"gcleveland.gif" }, { "presName":"Benjamin Harrison", "presDates":"1889-1893", "presNick":"Kid Gloves Harrison", "presImage":"bharrison.gif" }, { "presName":"Grover Cleveland", "presDates":"1893-1897", "presNick":"None", "presImage":"gcleveland.gif" }, { "presName":"William McKinley", "presDates":"1897-1901", "presNick":"Idol of Ohio", "presImage":"wmckinley.gif" }, { "presName":"Theodore Roosevelt", "presDates":"1901-1909", "presNick":"Trust-Buster", "presImage":"troosevelt.gif" }, { "presName":"William Howard Taft", "presDates":"1909-1913", "presNick":"None", "presImage":"whtaft.gif" }, { "presName":"Woodrow Wilson", "presDates":"1913-1921", "presNick":"Schoolmaster in Politics", "presImage":"wwilson.gif" }, { "presName":"Warren Gamaliel Harding", "presDates":"1921-1923", "presNick":"None", "presImage":"wgharding.gif" }, { "presName":"Calvin Coolidge", "presDates":"1923-1929", "presNick":"Silent Cal", "presImage":"ccoolidge.gif" }, { "presName":"Herbert Clark Hoover", "presDates":"1929-1933", "presNick":"None", "presImage":"hchoover.gif" }, { "presName":"Franklin Delano Roosevelt", "presDates":"1933-1945", "presNick":"FDR", "presImage":"fdroosevelt.gif" }, { "presName":"Harry S. Truman", "presDates":"1945-1953", "presNick":"Give 'Em Hell Harry", "presImage":"hstruman.gif" }, { "presName":"Dwight David Eisenhower", "presDates":"1953-1961", "presNick":"Ike", "presImage":"ddeisenhower.gif" }, { "presName":"John Fitzgerald Kennedy", "presDates":"1961-1963", "presNick":"JFK", "presImage":"jfkennedy.gif" }, { "presName":"Lyndon Baines Johnson", "presDates":"1963-1969", "presNick":"LBJ", "presImage":"lbjohnson.gif" }, { "presName":"Richard Milhous Nixon", "presDates":"1969-1974", "presNick":"None", "presImage":"rmnixon.gif" }, { "presName":"Gerald Rudolph Ford", "presDates":"1974-1977", "presNick":"Jerry", "presImage":"grford.gif" }, { "presName":"James Earl Carter Jr.", "presDates":"1977-1981", "presNick":"Jimmy", "presImage":"jecarter.gif" }, { "presName":"Ronald Wilson Reagan", "presDates":"1981-1989", "presNick":"The Gipper", "presImage":"rwreagan.gif" }, { "presName":"George Herbert Walker Bush", "presDates":"1989-1993", "presNick":"Poppy", "presImage":"ghwbush.gif" }, { "presName":"William Jefferson Clinton", "presDates":"1993-2001", "presNick":"Bill", "presImage":"wjclinton.gif" }, { "presName":"George Walker Bush", "presDates":"2001-2009", "presNick":"W", "presImage":"gwbush.gif" }, { "presName":"Barack Hussein Obama", "presDates":"2009-", "presNick":"None", "presImage":"bhobama.gif" } ] }
When I use the document.write to test it works fine if it's placed right before }); //end getJSON, but if it's place immediately after it is null. What am I missing?
Placing the document.write after //end getJSON means it will run before the JSON is retrieved.
The anonymous function you pass to .getJSON is called when the data comes back from the server. If you run the document.write after the //end getJSON it is called before the request comes back.
I don't like jQuery's $.each()
I would do it like this:
function parseJSON(JSONObj){
var array=new Array();
var count=0;
for(var Obj in JSONObj){
array[count]=JSONObj[Obj];
count++;
}
}
Please tell me if it is anything else you wanted

Categories