Scaffolded Upshot context not calling webapi? - javascript

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.

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

Meteor: Template is displayed although collection is not loaded yet

Hi fellow Meteor friends!
Please note: I am using Tom's router!
So I'm trying to only display my template when the mongo collection is ready but for some reason it does not work! :(
I first followed this post: LINK
So I have my publish functions in the server.js and I subscribe to these functions inside my router, so no Deps.autorun() involved here (btw: is this the right approach? Deps.autorun() did not work for me properly):
So I have something like:
'/myroute': function(bar) {
Meteor.subscribe("myCollection", bar, function() {
Session.set('stuffLoaded', true);
});
return 'stuffPage';
}
In the template, where the data loaded from "myCollection" is displayed, I will have something like this:
<template name="stuffPage">
{{#if stuffLoaded}}
<!-- Show the stuff from the collection -->
{{else}}
<p>loading!</p>
{{/if}}
</template>
For some reason "loading!" is never displayed.
Also, for a couple of milliseconds, the "old data" from the last time the same template was displayed (but with another "bar" value provided to the publish function --> different data) is displayed.
This of course is not good at all because for a couple of ms the user can see the old data and suddenly the new data appears.
To avoid this "flash" I want to display "loading!" until the new data is loaded but again: this does not work for me! :-(
What am I doing wrong?
Thx in advance for your help!
EDIT:
Ok so the problem with the answer in the first post provided by #user728291 is the following:
For some reason the router stuff get's called AFTER the Deps.autorun() ... what is wrong here? :( (please note: eventsLoaded == stuffLoaded.)
Where do you guys put your Deps.autorun() for the subscriptions or in other words: What's your code mockup for this?
I actually really think that my code mockup is just plain wrong. So how do you make different subscriptions based on the route (or in other words: based on the template which is currently shown)?
AND: Where do you put the Deps.autorun()? Inside the router.add() function? Or just inside of (Meteor.isClient)?
I think #user728291's answer is pretty spot on, I'd just add that Meteor.subscribe returns a handle that you can use to check readiness:
Keep a reference to the handle
Deps.autorun(function() {
stuffHandle = Meteor.subscribe(Session.get('bar'));
});
Then check it in your template:
{{#if stuffHandle.ready}}
...
{{/if}}
Template.barTemplate.helpers({stuffHandle: stuffHandle});
And control it via the session:
'/myroute': function(bar) {
Session.set('bar', bar);
return 'barTemplate';
}
Better to put the subscription in a Deps.autorun and use Session variable to pass arguments from the router. Also, make sure you are setting stuffLoaded to false before the subscribe runs. Otherwise it just keeps its old value.
'/myroute': function(bar) {
if ( ! Session.equals( "bar", bar ) ) {
Session.set( "stuffLoaded", false); //subscription needs to be run
Session.set( "bar", bar ); // this change will trigger Dep.autorun
}
return 'stuffPage';
}
Deps.autorun ( function (){
Meteor.subscribe("myCollection", Session.get( "bar" ), function() {
Session.set("stuffLoaded", true);
});
});
You might need some initial default values for the Session variables if you are not getting what you want on the first time the page loads.
First off, you may be missing the actual function name for the callback as demonstrated in this post.
Meteor.subscribe("myCollection", bar, function onComplete() {
Session.set('stuffLoaded', true);
});
Which seems to be great practice. I don't usually miss a beat using this method.
Secondly, I'm not sure subscriptions inside routes work well? I'd rather do the following:
'/myroute': function(bar) {
Session.set("myCollectionParam", bar)
return 'stuffPage';
}
So then the subsciption finally looks like this:
Meteor.subscribe("myCollection", Session.get("myCollectionParam"), function onComplete() {
Session.set('stuffLoaded', true);
});
OR (not sure which works correctly for you, depending on your publish function):
Meteor.subscribe("myCollection", {bar: Session.get("myCollectionParam")}, function onComplete() {
Session.set('stuffLoaded', true);
});
Good luck!
EDIT
Just mentioning something about the publish function:
While Session.get("myCollectionParam") could return null, you can ensure the behaviour a bit more by using the following publish method:
Meteor.publish("myCollection", function(myCollectionParam) {
check(myCollectionParam, String);
return MyCollection.find({_id: myCollectionParam});
});

RequestContext and Ajax status in PrimeFaces

I need to handle globally ajax responses. Everything works ok, out of the box, when I only want to call normal javascript action without any arguments. Than I can use p:ajaxStatus controll, and application behaves in a correct way.
What I actually now need to do, is to handle situation, when during ajax request there was externalContext.redirect() call. It happens only in one place in application, but it is called from many places.
I was thinking, that I can for instance add callback param in RequestContext. But how can I access this param in javascript?
While watching in firebug, I can see that callbackParam is returned in json response, but how can I access this value in javascript?
It's been added as a property of default args object which is available in oncomplete context.
So, for example
RequestContext.getCurrentInstance().addCallbackParam("foo", "bar");
is available as
oncomplete="console.log(args.foo)"
See also:
PrimeFaces RequestContext showcase
Update: as per the comments, that turns out to fail in <p:ajaxStatus>. I sugges to report it as a bug to PF guys, that the arguments are not available in <p:ajaxStatus oncomplete>. In the meanwhile, you can workaround it with the following script which is loaded by <h:outputScript target="head"> inside the <h:body> (to guarantee that it's loaded after PrimeFaces script):
var originalPrimeFacesAjaxUtilsSend = PrimeFaces.ajax.AjaxUtils.send;
PrimeFaces.ajax.AjaxUtils.send = function(cfg) {
var originalOncomplete = cfg.oncomplete;
cfg.oncomplete = function() {
ajaxStatusOncomplete.apply(this, arguments);
if (originalOncomplete) {
originalOncomplete.apply(this, arguments);
}
};
originalPrimeFacesAjaxUtilsSend.apply(this, arguments);
};
function ajaxStatusOncomplete(xhr, status, args) {
// Do your thing here.
}
In p:ajaxStatus params available via PrimeFaces.ajax.Queue.xhrs
For example:
oncomplete="console.log(PrimeFaces.ajax.Queue.xhrs[0].pArgs.foo)"

How do I handle URL variables in Parse.com?

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/

Avoiding eval when executing js returned from ajax call

I want to make an ajax call that will return a json object. One of this JSON object's properties will be the string of a function to be executed in the client. I realise this can easily be solved by using eval, but seeing the many disadvantages of eval, I'd rather avoid it. My question is:
Can I in some way return from the server some js code and execute it without resorting to eval?
As requested, here's some example code:
Server (Node.js):
var testFunc = function() {
alert('h1');
};
app.get('/testPack', function(req, res) {
var template = jade.render('h1 hi');
res.send({
template : template,
entity : testFunc.toString(),
data : {
id: "OMG I love this"
}
});
});
Client:
$(document).ready(function() {
$.ajax({
url: '/testPack',
success: function(data) {
$('body').append($(data.template))
alert(data.data.id);
var entity = eval(data.entity);
entity();
}
})
})
Of course, the returned function called entity wouldn't do such a silly thing, it would expose an API of the returned widget.
Just to clarify, I'd like to avoid having to make a separate call for the javascript itself. I'd rather bundle it with the template and data to render.
Easiest way to do that, is not to call a server through an ajax, but instead to create a new script tag on the page with the url pointing to a RESTful web-service that would output pure JavaScript (not JSON). That way your output will be evaluated by the browser directly without the use of eval.
To expand a little on my answer:
To get around the problems of running script in the global context you could do some tricks. For example, when you are adding script tag to the head, you can bind onload event (or rather fake onload event, since IE doesn't support onload on the script tag) to it, and if your response from the server will be always wrapped in the the function with a known name, you could apply that function from within your object. Example code below (this is just an example though):
function test ()
{
this.init = function ()
{
var script = document.createElement("script");
script.type = "text/javascript";
script.language = "javascript";
script.src = "test.js";
var me = this;
window.callMe = function () { me.scriptReady(me); };
var head = document.getElementsByTagName("head")[0];
head.appendChild(script);
};
this.scriptReady = function (object)
{
serverResponse.call(object);
};
this.name = "From inside the object";
this.init();
}
var t=new test();
The server response should look something like this:
function serverResponse()
{
alert(this.name);
}
window.callMe();
In this case, everything inside serverResponse() will use your object as "this". Now if you modify your server response in this way:
function serverResponse()
{
this.serverJSONString = { "testVar1": "1", "testVar2": 2 };
function Test()
{
alert("From the server");
}
Test();
}
window.callMe();
You can have multiple things being returned from the server and with just one response. If you don't like just setting variables, then create a function in your main object to handle JSON string that you can supply by calling this function from your response.
As you can see, it's all doable, it really doesn't look pretty, but then again, what you are trying to do is not pretty to begin with.
P.S. Just inserting a string inside tag will not work for IE, it will not allow you to do that. If you don't have to support IE, then you could get away with just inserting server response inside a newly created script tag and be done with it.
P.P.S. Please don't use this code as is, cause I didn't spend too much time writting it. It's ugly as hell, but was just ment as an example:-)
No, you can't do this by definition, because JavaScript functions are not valid JSON. See the spec here:
http://www.json.org/
If you're returning a string, then that's what it is: just a string. You can't evaluate it without eval. You can call whatever else you're returning whatever you want, but please don't call it JSON.
Here's an example of how I think this could work.
The json object represents what is returned from the server. The c and d properties contain function names as strings. If those functions are properties of some other object which exists in your page, then you should be able to call them using the object["property"] accessor.
See it working on jsFiddle: http://jsfiddle.net/WUY4n/1/
// This function is a child of the window object
window.winScopedFunction = function() {
alert("ROCK THE WIN");
}
// This function is a child of another object
var myObject = {
myFunction : function() {
alert("ROCK ON");
}
};
// pretend that this json object was the result of an ajax call.
var jsonResultFromServer= {
a : 1,
b : 2,
c : "myFunction",
d : "winScopedFunction"
};
// you can call the local functions like so
myObject[jsonResultFromServer.c]();
window[jsonResultFromServer.d]();
Yes, there's a way, but it has the exact same disadvantages as eval.
You can use the Function constructor to create a new function, and then call it. For example:
new Function(code)();
http://code.google.com/p/json-sans-eval/ is a fast JSON parser that does not use eval, and JSON.parse is becoming increasing widely available in new browsers. Both are excellent alternatives to eval for parsing JSON.
You can use the trick that Google does with Google Charts.
<html>
<head>
<script>
function onWorkDone(data) {
console.log(data);
}
</script>
<script src="callback.js"></script>
</head>
</html>
Then your callback.js is:
function doWork(callback) {
callback({result: 'foo'});
}
doWork(onWorkDone);
Basically, your script will call onWorkDone when the doWork completed. You can see a working example here:
http://jsfiddle.net/ea9Gc/
Do you have some example cases? Some things I can think of is you that you can just have a regular function inside your js file, and your server will return some parameters for your function to execute. You can even specify what function to use! (Isn't that amazing?)
// your js file
var some_namespace = {
some_function : function(a, b){
// stuff
}
}
// your server output
{
some_other_data: "123",
execute: {
func: "some_namespace.some_function",
params: [1, 2]
}
}
// your ajax callback
function(r){
window[r.execute.func].apply(this, r.execute.params);
}
The reasons of not using eval
Well, you already said it yourself. Don't use eval. But you have a wrong picture regarding why.
It is not that eval is evil. You are getting the reason wrong. Performance considerations aside, using eval this way allows a sloppy programmer to execute code passed from server on the client. Notice the "passed from server" part.
Why never execute code passed from server
Why don't you want to execute code passed from the server (incidentally that's what you're planning to do)?
When a browser executes a script on a web page, as long as the web site is valid -- i.e. really yours, and not a malware site pretending to be yours trying to trick your users -- you can be reasonably sure that every bit of code the browser is running is written by yourself.
Hacker's heaven -- script injection attacks
Now, if you are passing data from the server to your web application, and that data contains executable functions, you're asking for trouble. In the long, twisted journey of that data going from your server to your client's browser, it goes through the wild west called the Internet, perhaps through multiple layers of proxies and filters and converters, most of which you do not control.
Now, if a hacker is hiding somewhere in the middle, takes your data from the server, modify the code to those functions to something really bad, and sends it away to your client, then your client browser takes the data and executes the code. Voila! Bad things happen. The worse is: you (at the server side) will never know that your clients are hacked.
This is called a "script injection attack" and is a serious sercurity risk.
Therefore, the rule is: Never execute functions returned from a server.
Only pass data from server
If you only accept data from a server, the most that can happen whan a hacker tempers with it is that your client will see strange data coming back, and hopefully your scripts will filter them out or handle them as incorrect data. Your client's browser will not be running any arbitrary code written by the hacker with glee.
In your client-side script, of course you're sticking to the Golden Rule: Do not trust ANY data coming through the Internet. Therefore you'd already be type-check and validating the JSON data before using it, and disallowing anything that looks suspicious.
Don't do it -- pass functions from server and execute on client
So, to make a long story short: DON'T DO IT.
Think of another way to specify pluggable functionalities on the browser -- there are multiple methods.
I've had this same question, and I fixed it this way:
File: functions.js.php?f=1,3
$functions=array(
'showMessage' => 'function(msg){ alert(msg); }',
'confirmAction' => 'function(action){
return confirm("Are you sure you want to "+action+"?");
}',
'getName' => 'function getName(){
return prompt("What is your name?");
}'
);
$queried = explode($_REQUEST['f']);
echo 'var FuncUtils = {'; // begin javascript object
$counter=1;
foreach($functions as $name=>$function){
if(in_array($counter, $queried))
echo '"'.$name.'":,'.$function.',';
$counter++;
}
echo '"dummy":null };'; // end javascript object
File: data5.json
{
"action" : ['confirmAction','exit']
}
File: test.js
$(document).ready(function(){
$.getScript('functions.js.php?f=1,3');
});
function onBeforeExit(){
$.getJSON('data5.json', function(data) {
var func = data.action.shift();
FuncUtils[func].apply(null, data.action);
});
}

Categories