Framework7 routes, load page from existing JSON string - javascript

I have the JSON data load at the start, and also pull to refresh. During these times a small delay is expected. When going between pages, it should be snappy, so I am looking to use this already requested JSON for my page content. One of the JSON objects is the entire (small enough) html page.
I cannot find a way to use this, and instead am following the examples making a second JSON get request before loading each page (article). I would rather just load the JSON data once at the start and use it until refreshed with pull-to-refresh.
* Currently Working, but using a second JSON get *
{
path: '/article/:article_id/',
// This works after much turmoil.
// sadly have to do a second json call. could have got with initial.
async: function (routeTo, routeFrom, resolve, reject) {
//Testing
// import('window.TodayJsonDB['+ routeTo.params.article_id +'][\'html\']');
// window.TodayJsonDB[routeTo.params.article_id]['html'];
// [data['article']['article_html']
// console.log(routeTo);
// Get external data and return template7 template
this.app.request.json('/__php/json1.php', { one: 1, article_id: routeTo.params.article_id }, function (data) {
// console.log(data['article'][0]['article_html']);
resolve(
// DOM locked until resolve returned.
// object with resolved route content. Must contain one of:
// url, content, template, templateUrl, component or componentUrl
{
content: data['article'][0]['article_html'],
},
);
});
}
// A day of testin but couldnt figure out how to use existing json feed.
//asyncComponent: () => import('window.TodayJsonDB['+ params.article_id +'][\'html\']'),
//el: window.TodayJsonDB[params.article_id]['html'],
//el: import('window.TodayJsonDB['+ params.article_id +'][\'html\']'),
//template: import('window.TodayJsonDB['+ params.article_id +'][\'html\']'),
//template: import('window.TodayJsonDB[' + params.article_id +'][html]'),
//asyncComponent: () => import('window.TodayJsonDB[' + params.article_id +'][html]'),
//asyncComponent: () => import('window.TodayJsonDB[' + $route.params.article_id +'][html]'),
//asyncComponent: () => import('window.TodayJsonDB[' + {{article_id}} +'][html]'),
//asyncComponent: () => import('window.TodayJsonDB[11][\'html\']'),
//content: window.TodayJsonDB[':article_id']['html'],
},
I already have this json get already; loaded when the app opens and updated with pull-down: window.TodayJsonDB
which contains:
window.TodayJsonDB[data['article'][i]['article_id']] = new Array();
window.TodayJsonDB[data['article'][i]['article_id']]['article_id'] = data['article'][i]['article_id'];
window.TodayJsonDB[data['article'][i]['article_id']]['title'] = [data['article'][i]['article_title']];
window.TodayJsonDB[data['article'][i]['article_id']]['content'] = [data['article'][i]['article_content']];
window.TodayJsonDB[data['article'][i]['article_id']]['html'] = [data['article'][i]['article_html']];
So my question is; how can I use the content of window.TodayJsonDB[article_id]['html'] to appear as the page content instead of having to do another JSON call when the user clicks a link.
My attempts in the code, commented out. Any other suggestions on how to approach the entire thing differently very much welcome.
Thanks as ever.
n.b. I tagged Vue as I believe closely related with Framework7. I am not using Vue.

Found a solution, my working code snippet is below. I used the same async section and converted the array output to a string using toString(). Only appears to work in the async section.
Can now load up the JSON for everything at the start, one JSON call.
Maybe will help someone else with Framework7. Good Luck!
{
path: '/article/:article_id/',
async: function (routeTo, routeFrom, resolve, reject) {
// Do we already have the JSON for the page?
if (typeof window.TodayJsonDB[routeTo.params.article_id]['html'] != "undefined") {
resolve({
content: (window.TodayJsonDB[routeTo.params.article_id]['html'].toString()),
});
}
else{
// Try and get it
this.app.request.json('/__php/json1.php', { one: 1, article_id: routeTo.params.article_id }, function (data) {
resolve(
{
content: data['article'][0]['article_html'],
},
);
});
}
}

Related

Quit AJAX loop or find alt to reading in list of html pages to do a compare

I need to get this small script inserted onto all of my website pages.
The script has to contain the token set for that domain.
I have 21 different domains.
Each domain has an HTML page with all the sites under that domain listed on it.
It isn't as easy as wwww.site.com/domain/path, not all the sites are under the same 'domain name' but are considered under that 'domain'.
So my thought was to write a script that upon the page loading, read in the site pathname and compare it to each list until a match is found.
Look at my array of {domain, tokens} and find the correct token for that domain and have a function write the script with the token and insert it into the page.
The Issue: AJAX will not quit the loop of searching the list of site URLs after a match has been found so this is all a massive drain on the server.
I know there have been several stackoverflow questions related to that very problem and I have tried all of the solutions posted. My real question is, how can I not use AJAX to read in and do the compare for the site pathnames?
Is there a better way to solve this problem?
*The key to using the 21 different HTML pages with the listed sites for each is, that list is dynamically updated with new site releases and deleted sites which happen frequently enough.
The script I need to be inserted is an analytics tracking code.
Latest Attempt at this (pseudo code because I can not post direct links/information)
let tokens = [{ domain: "Example",
url: "//example.html",
token: "ExampleToken"
},
etc
];
let index = 0;
jQuery( document ).ready(function()
{
loopyloop(); //start index at 0
});
function loopyloop()
{
jQuery.ajax({
type: "GET",
ajaxToken: index,
url: tokens[index].url,
success: function(data)
{
findToken(data);
},
error: function() {
console.log('fail');
}
});
}
function findToken(data)
{
//data is a very large string of <html> format, use replace to find a match with the domain
var urlRegex = /(https?:\/\/[^\s]+)/g;
data.replace(urlRegex, function(url) {
//compare the found URLs to the pathname/URL of the page
if (url.toLowerCase().indexOf(window.location.pathname.toLowerCase()) >= 0)
{
create_script(tokens[index].token, tokens[index].domain);
return false;
}
else if(index+1 < tokens.length)
{
index += 1;
console.log(index, tokens[index].domain);
loopyloop();
}
});
}
//this part has been tested and works correctly when called, no need to post this actual code
function create_script(token, domain)
{
console.log('token found: '+ domain, token);
}
I would try converting it to an async function, so that you can do a proper loop with await and break out of it when you're ready
Something potentially resembling this:
async function loopyLoop() {
try {
while(true) {
let data = await axios.get(``);
// some logic to extract token and compare it
if (somethingsomething) {
continue;
} else if (somethingelse) {
break;
}
}
} catch(e) {
console.log('loop errored');
console.log(e.toString());
}
}

Trying to set the state in react via a loop and a ajax request

I am fooling around with a loop and a ajax request in react I cannot seem to get working. Its suppose to loop over, set the object array and then push that object array to the state for later use.
The issue is that I am failing at promises in general. I am using this concept from the react docs to set the state of a component upon mounting to return an array of "links".
/** #jsx React.DOM */
var Temp = {
object: new Array()
}
var CommentsRow = React.createClass({
getInitialState: function(){
return {
href: ''
}
},
componentDidMount: function(){
var self = this
this.props.comments.slice(0, 5).map(function(comment){
var postUrl = window.Development.API_URL + 'posts/' + comment.post_id
$.get(postUrl, function(post){
Temp.object.push(post.post.title);
if (self.isMounted()) {
self.setState({
href: Temp.object
});
}
});
});
},
render: function() {
console.log(this.state)
}
});
The gist of whats going on above is:
I have a bunch of comments coming in and I take the first five. From there I loop over each comment object and grab the title, creating my api link. With that I want to say get me the post based on this link, assuming it works we then want to set a temp object, this will create "five arrays" each going from a count of 1,2,3,4 and finally 5 elements.
from there we take that and set the state. This part works, but because its a ajax request the state out side the request is empty even if I use the if (isMounted()){ ... } option.
any idea how I can set the state doing something like this and still have access to it?
You either want async.js or promises to help manage multiple async actions. Async integrates a bit better with jQuery, so I'll show it with that.
componentDidMount: function(){
async.map(this.props.comments.slice(0, 5), function(comment, cb){
var postUrl = window.Development.API_URL + 'posts/' + comment.post_id;
$.get(postUrl, function(data){
cb(null, {title: data.post.title, href: ???});
});
}, function(err, posts){
// posts is an array of the {title,href} objects we made above
this.setState({posts: posts});
}.bind(this));
}

Waiting on collection data prior to rendering a subview

I am building what should be a fairly simple project which is heavily based on Ampersand's starter project (when you first run ampersand). My Add page has a <select> element that should to be populated with data from another collection. I have been comparing this view with the Edit page view because I think they are quite similar but I cannot figure it out.
The form subview has a waitFor attribute but I do not know what type of value it is expecting - I know it should be a string - but what does that string represent?
Below you can see that I am trying to fetch the app.brandCollection and set its value to this.model, is this correct? I will need to modify the output and pass through the data to an ampersand-select-view element with the correct formatting; that is my next problem. If anyone has suggestions for that I would also appreciate it.
var PageView = require('./base');
var templates = require('../templates');
var ProjectForm = require('../forms/addProjectForm');
module.exports = PageView.extend({
pageTitle: 'add project',
template: templates.pages.projectAdd,
initialize: function () {
var self = this;
app.brandCollection.fetch({
success : function(collection, resp) {
console.log('SUCCESS: resp', resp);
self.brands = resp;
},
error: function(collection, resp) {
console.log('ERROR: resp', resp, options);
}
});
},
subviews: {
form: {
container: 'form',
waitFor: 'brands',
prepareView: function (el) {
return new ProjectForm({
el: el,
submitCallback: function (data) {
app.projectCollection.create(data, {
wait: true,
success: function () {
app.navigate('/');
app.projectCollection.fetch();
}
});
}
});
}
}
}
});
This is only the add page view but I think that is all that's needed.
The form subview has a waitFor attribute but I do not know what type of value it is expecting - I know it should be a string - but what does that string represent?
This string represents path in a current object with fixed this context. In your example you've waitFor: 'brands' which is nothing more than PageView.brands here, as PageView is this context. If you'd have model.some.attribute, then it'd mean that this string represents PageView.model.some.attribute. It's just convenient way to traverse through objects.
There's to few informations to answer your latter question. In what form you retrieve your data? What do you want to do with it later on?
It'd be much quicker if you could ping us on https://gitter.im/AmpersandJS/AmpersandJS :)

Parse.com Files Not Updating, lead to broken links from data browser

So in my js code, the user is making mosaic images. When they press upload, I create a new object and all is good, my code works perfectly. I then save the id to that object that was just uploaded. If the user presses the upload button again, I want to simply use that same object id and clear out the files that were saved before and use the newest version. All of my saves, updates, and everything appear to be working just fine. When I go to the data browser though, I see the files but when I click, the link is broken. (Which doesn't seem it like it should even be possible). 95% of my code is below, there is some stuff outside of that to generate the mosaic image and to store the id returned. How can I avoid these broken links?
var ins_file = new Parse.File("Instructions.png", { base64: img_ins_InBase64 }, "image/png");
var pretty_file = new Parse.File("Pretty.png", { base64: img_pretty_InBase64 }, "image/png");
ins_file.save().then(function () {
}, function (error) {
console.log("Instruction File couldn't be saved")
// The file either could not be read, or could not be saved to Parse.
});
pretty_file.save().then(function () {
}, function (error) {
console.log("Mosaic File couldn't be saved")
// The file either could not be read, or could not be saved to Parse.
});
var mosaicClass = Parse.Object.extend("Mosaics");
var mosaicObj = new Parse.Object("Mosaics");
var query = new Parse.Query(mosaicClass);
query.get(parseId, {
success: function (objToUpdate) {
// The object was retrieved successfully. SIMPLY UPDATE
objToUpdate.set("img_ins", ins_file);
objToUpdate.set("img_pretty", pretty_file);
objToUpdate.save().then(function () {
console.log("Initial Image updated");
var ins_img_url = objToUpdate.get('img_ins').url();
var pretty_img_url = objToUpdate.get('img_pretty').url();
objToUpdate.set("img_ins_url", ins_img_url);
objToUpdate.set("img_pretty_url", pretty_img_url);
objToUpdate.save();
console.log("Mosaic updated, id was: " + objToUpdate.id);
parseId = objToUpdate.id;
}, function (error) {
console.log("File couldn't be updated")
// The file either could not be read, or could not be saved to Parse.
});
},
error: function (object, error) {
// The object was not retrieved successfully.
// parseId was null so make a new thing
mosaicObj.set("img_ins", ins_file);
mosaicObj.set("img_pretty", pretty_file);
mosaicObj.save().then(function () {
console.log("Initial Images uploaded");
var ins_img_url = mosaicObj.get('img_ins').url();
var pretty_img_url = mosaicObj.get('img_pretty').url();
mosaicObj.set("img_ins_url", ins_img_url);
mosaicObj.set("img_pretty_url", pretty_img_url);
mosaicObj.save();
console.log("Mosaic Saved, id was: " + mosaicObj.id);
parseId = mosaicObj.id;
}, function (error) {
console.log("File couldn't be saved")
// The file either could not be read, or could not be saved to Parse.
});
}
});
It appears you're not waiting for the files to save before trying to assign them to a parse object. Async JS will get you every time.
You should be saving the file object on the parse object only after the save, inside the then. You can put both file saves in an array and use Parse.Promise.when([promise1, promise2]).then(...); too.

WinJS: Loading data

I'm trying to develop my first Windows 8 Store app (HTML/JS). I am using the Grid App Template which suites my Needs I think the best.
This is my model:
I have three entities: 1. GalleryCategory 2. Gallery 3. GalleryItem.
A Gallery is linked to exactly one Category. A GalleryItem is linked to exactly one Gallery...so nothing fancy here...
I'm using the out of the box data.js file to load all categories and all galleries on the Startup of the app. But when I open the galleryDetail.html (which is supposed to Show all the Images of the particular Gallery) I want to load all Images of the Gallery then. (to avoid to much loading on the beginning).
And now I'm finally coming to the Point that I do not understand:
How can I manage this?? I mean
WinJS.UI.Pages.define("/pages/galleryDetail/galleryDetail.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
var item = options && options.item ? Data.resolveItemReference(options.item) : Data.items.getAt(0);
element.querySelector(".titlearea .pagetitle").textContent = item.group.title;
element.querySelector("article .item-title").textContent = item.title;
element.querySelector("article .item-subtitle").textContent = item.subtitle;
element.querySelector("article .item-image").src = item.backgroundImage;
element.querySelector("article .item-image").alt = item.subtitle;
element.querySelector("article .item-content").innerHTML = item.content;
element.querySelector(".content").focus();
var galleryId = item.key;
WinJS.xhr({ url: "http://someUrlToAnAspNetWebsite/Handlers/GalleryItemsHandler.ashx?galleryId=" + galleryId }).done(
// Complete function
function (response) {
var items = JSON.parse(response.responseText);
items.forEach(function (item) {
galleryItemsList.push(item);
});
dataList = new WinJS.Binding.List(galleryItemsList);
var galleryItemsListView = document.getElementById('galleryItemsListView').winControl;
galleryItemsList.itemDataSource = dataList.dataSource;
},
// Error function
function (response) {
// handle error here...
},
// Progress function
function (response) {
// progress implementation goes here...
}
);
},
my Problem is obivous...the ready function continues / Ends before the data is retrieved...as the async call takes a while.
But I thought using the promise (.done()) will do this for me (synchronising the threads)?? Or do I need to use the join() function. If so, where and how?? Sorry for my issues with this...
Thanks for any help...
The ready function itself is an async function, so you only have to return a promise to tell its caller that its not done until some promise is resolved. So you can fix your issue with 7 key strokes. Just add return before the WinJS.xhr call.

Categories

Resources