How do I handle URL variables in Parse.com? - javascript

I generally access my Parse app by going to www.mysite.com.
However, I want to be able to do something like www.mysite.com/code or www.mysite.com?page=code, and for this to show a specific view within the app, without having to click through. In other words, I want to detect that a GET variable is present, and use it to determine which view to show.
Can anyone point me in the right direction?

You can use Backbone's Router. There's an example in the Anypic.org source code you can use.
var AppRouter = Backbone.Router.extend({
routes: {
"pic/:object_id": "getPic",
"*actions": "defaultRoute"
},
getPic: function(object_id) {
App.showLandingPage();
var query = new Parse.Query(Photo);
query.include("user");
query.get(object_id, {
success: function(photo) {
App.landingPageView.showPhoto(photo);
},
error: function(object, error) {
console.error(error);
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
App.landingPageView.showError();
}
});
},
defaultRoute: function(actions) {
App.showHomePage();
}
});
In this example, navigating to https://anypic.org/pic/XXXXX will call getPic and pass along the value of XXXXX to the getPic function.

I don't have much familiarity with parse.com, but if you just want to access GET variables within javascript, it's not terribly difficult:
http://www.onlineaspect.com/2009/06/10/reading-get-variables-with-javascript/

Related

Additional url attribute at nightwatch page object

I was trying to add an additional url attribute as a function to my page-object while using nightwatchjs.
Like:
module.exports = {
url: function() {
return this.api.launchUrl + '/content/site1.xhtml';
},
cancelUrl: function() {
return this.api.launchUrl + '/content/cancel_site1.xhtml';
}
}
Anyhow nightwatch is not able to get that 2nd attribute cancelUrl, ie undefined.
Why is that so? Shouldn't nightwatch be able to access that attribute as it is nothing more than a function call returning a string or am I misunderstanding a javascript or special page-object concept?
--
I am aware that there should be a page-object for each site so there should not be a 2nd site. Anyhow I would like to understand why this is not working technically.
Not sure I can answer the "why" (other than to say that when nightwatch loads up your page objects as globally available it must be wrapping your js file and filtering on 'known' functions) but I can offer a solution: add a command to your page object with the desired function. For example:
let pageCommands = {
cancelUrl: function() {
return this.api.launchUrl + '/content/cancel_site1.xhtml';
}
};
module.exports = {
commands: [pageCommands],
...
}
It's not the typical use of page commands, but your test would then be able to access the cancelUrl function on the page object instance.
More on page commands here

Loading Custom Component ViewModel from JavaScript file

I'm trying to create a custom component loader within knockout but I'm struggling with the view model. Essentially I want to remotely go grab both the HTML template and the JavaScript view model, but in this instance I don't want to use a traditional AMD module loader.
I've managed to get some of this working, specifically loading the HTML template but I can't figure out how to load the view model. Before I start here's my directory structure:
-- index.html
-- customerLoader.js
-- comps
   -- myCustom.html
   -- myCustom.js
So I've created my component loader like so. getConfig basically takes the name of the component and turns that into a path for the viewModel and the html template.
var customLoader = {
getConfig: function(name, callback) {
callback({ template: "comps/" + name + ".html", viewModel: "comps/" + name + ".js" });
},
loadTemplate: function(name, templateConfig, callback) {
console.log("loadTemplate", name, templateConfig);
$.get(templateConfig, function(data) {
callback(data);
});
},
loadViewModel: function(name, templateConfig, callback) {
console.log("loadViewModel", name, templateConfig);
$.getScript(templateConfig, function(data) {
callback(data);
});
}
};
ko.components.loaders.unshift(customLoader);
This successfully makes a request to load the template, which brings back some basic content. What I'm struggling with is the view model. I'm not sure what should be in the target of my JavaScript file?
I assumed that I'd want to return a function that would take some parameters, most likely a params object. However if I try and do this I get an error, telling me the JavaScript is invalid:
Uncaught SyntaxError: Illegal return statement
This is the current content I've got that is producing this error:
return function(params) {
console.log("myCustom.js", name, viewModelConfig);
// Add a computed value on
params.bookNum = ko.computed(function() {
switch(this.title()) {
case "A": return 1;
case "B": return 2;
case "C": return 3;
default: return -1;
}
});
//ko.components.defaultLoader.loadViewModel(name, viewModelConstructor, callback);
};
So ultimately I'm not sure how to achieve this, but I guess there are 3 basic questions that explain the gaps in my understanding:
What should my "view model" JavaScript file contain exactly? A function? An object? etc...
Do I need to call the ko.components.defaultLoader.loadViewModel at all?
Within my customLoader what should loadViewModel() be doing with the result of the jQuery callback? I'm not sure if I get back a JavaScript object, or just a string?
I'm open to achieve this in a different way if need be (e.g. not using jQuery but getting files a different way), but I don't want to use a module loader (e.g. require.js/curl.js in this instance).
First lets figure out what is happening...
From the docs:
This ($.getScript()) is a shorthand Ajax function, which is equivalent to:
$.ajax({
url: url,
dataType: "script",
success: success
});
And from jQuery.ajax():
...
dataType: ...
"script": Evaluates the response as JavaScript and returns it as plain text.
So your code is fetched, evaluated and then would have been returned as text, but evaluation first fails because you can't return if you're not within a function.
So what can be done? There are several options:
Use a module loader.
jQuery isn't a module loader, and as such it doesn't have the ability to parse fetched code and create a value / object from that code. A module loader is designed specifically for this task. It will take a script written in a specific pattern and "evaluate" it into a value (typically an object with 1 or more properties).
Change your script to a legal script
Because it's illegal to have a return statement in global code, your current code fails. You could however create a named function (or a variable with a function expression) and then use that name to reference that function. It could look like this:
function myCreateViewModel(param) {
// whatever
}
And the usage would be:
$.getScript(templateConfig, function() {
callback(myCreateViewModel);
});
The downside here is that if you ever go through that code path twice in the same page, your script will overwrite the old declaration. That might not ever be a problem, but it feels dirty.
Not use $.getScript(), use $.ajax() (or $.get()) with dataType: 'text' and evaluate yourself.
Remove the return from your code, and wrap it with an eval(). It will be evaluated as a function expression, the return value of the eval will be your function, and you could pass that directly to the callback:
$.get({
url: templateConfig,
dataType: 'text',
success: function(text) {
callback(eval(text));
}
});
This will work, but it will use the frowned upon eval(), which is exposing you to various risks.

Overriding Backbone's URL function to Fetch Data From Local Store

I am writing a caching system which works with backbone (which I am still new to).
The system is as follows:
First try to get the data from local storage and upon failing to do so then make the call to the server.
Can I overwrite the url() function to first check local storage and then make the call or should this mechanism be outside url() and backbone ? i.e. Maybe this is using backbone incorrectly ?
Thanks !
Edit:
As requested I am adding more details.
I am using backbone.js the specific library I am using via require.js is backbone_amd-min.
Code sample:
Model:
define([ 'jquery', 'underscore', 'backbone', 'cacher' ], function($, _, Backbone, cacher) {
var article = Backbone.Model.extend({
defaults : {
title : '',
content : '',
},
parse : function(response, xhr) {
return response;
},
url : function() {
//What I want to do is (specify where to retrieve the article):
var articleInCache = cacher.inCache(this.flag);
if(articleInCache)
return localStorage
else
return remoteUrl;
},
flag : '2'
});
return article;
});
Can I modify url() or should I be modifying fetch()
To answer this question you first need a quick primer on fetch. When you do:
someModel.fetch();
What happens behind the scenes is:
fetch uses the url (or urlRoot) method/property to figure out where to make the AJAX call
fetch uses the sync method to actually make the AJAX call.
After the AJAX call returns, fetch passes what it gets back through parse, then passes that to set.
Given that, you clearly don't want to override url, as it has nothing to do with the actual AJAX part that you want to replace. You could override fetch, and that would work:
fetch: function() {
var fetched = this.getLocalVersion();
if (fetched) {
return new $.Deferred().resolve();
} else {
return this.prototype.fetch.apply(this, arguments);
}
}
However, that won't help you when you want to save or delete your Model, so really sync (which covers all AJAX operations) is probably the ideal method to override.
... of course, there's no point in re-inventing the wheel, so rather than override anything your best bet is probably to use one of the existing Backbone LocalStorage libraries.

Scaffolded Upshot context not calling webapi?

I am following a very simple tutorial by Steve Sanderson and it seems like the scaffolded script does not call my webapi:
cshtml code:
#(Html.UpshotContext().DataSource<Yoga.Controllers.YogaController>(x => x.GetAllBugs()))
Generated script:
upshot.dataSources = upshot.dataSources || {};
upshot.metadata({...});
upshot.dataSources.AllBugs = upshot.RemoteDataSource({
providerParameters: { url: "/api/Yoga/", operationName: "GetAllBugs" },
entityType: "BugView:#Yoga.Models",
bufferChanges: false,
dataContext: undefined,
mapping: {}
});
and it was called after page is loaded:
$(function() {
var dataSource = upshot.dataSources.AllBugs;
dataSource.refresh(function(results)){
//error here, `result` is an null object
alert(results);
});
});
I placed a breakpoint at my GetAllBugs() member in the controller, and it was never hit.
However, when i visit the uri directly, http://localhost/api/yoga/getallbugs i get the expected result. (and the breakpoint was hit)
I can't seem to figure out what is going on with the scaffolded upshot script.
Thanks
Try the following code:
dataSource.refresh(function (entities, total){
alert(entities);
});
Also, go to the Network tab of firebug/developer console, or start up Fiddler, and check whether the request to the controller is actually sent or not. If it is sent, then your problem is on controller, probably not mapping the action correctly.

Javascript scope issue, inside an anonymous function

Sorry I couldn't be anymore specific with the title.
I'm building a web-site (personal), which displays different content to the user depending on the query string that is used in the url.
e.g. page=home.html would display home.html
The websites Javascript is wrapped inside an object, with each value containing different data, some pseudo code:
(function(){
var wrapper = {
init: function(){
//Runs on document ready
this.foo();
this.nav.render();
},
foo: function(){
//Some functionality goes here for the website, e.g. Display something from an API
},
nav: {
//Functionality to handle the navigation, has different properties
config: {
//Contains the config for nav, e.g. page names + locations
dir: '/directory/to/content/',
pages: {
page_name: wrapper.nav.config.dir + 'page_value'
}
},
render: function(){
//some code
},
routes: function(){
//some code}
}
}
};
$(function(){
wrapper.init();
});
})();
My problem is that I'm trying to prepend the dir value to each of the page values (inside the object where the pages are defined), expecting to get the output of (in this pseudo code case) of directory/to/content/page_value, but instead dir is undefined when I'm trying to access it, I've tried the following to achieve what I want:
wrapper.nav.config.dir + 'page_value'
I've been playing around with the last 30 minutes trying to find out what I'm doing wrong, and even thought about hard-coding the URL in for each page.
The reasoning for wanting to do this is that my local development server and web host have different directory structures, so I don't want to re-write the URL's each time I want to develop + publish. As for why everything is wrapped inside an object, I thought it would be easier to maintain this way.
Hopefully the answer is simple and it's just an amateur mistake / lack of understanding.
The issue is that you can't refer to a variable that is being defined in that very definition.
So, inside the definition of wrapper, you can't refer to wrapper. And, inside the definition of config, you can't refer to config either and so on.
The usual design pattern for solving this is to initialize as much as you can in the declaration of your data structure and then do the rest in .init() when you can freely access all of it.
Change the first two lines to:
var wrapper = null;
(function(){
wrapper = {
Otherwise, the wrapper is a local variable to your anonymous function.
The problem is that you're still busy defining the wrapper when you ask for its value, which is why it's still undefined.
The code below fails too:
var x = {
y:"1",
z:x.y
}
Why not:
//...
init: function(){
//Runs on document ready
this.foo();
var config = this.nav.config;
for (var page in config.pages) {
config.pages[page] = config.dir + config.pages[page];
}
},
//...

Categories