I'm using the StratifiedJS library's waitFor construct.
function myFunction() {
// some declarations
waitfor() {
AsyncService.getThisDone().then(function(result) {
// some more calculation
resume();
});
}
}
I am getting unexpected '{' on the line where waitfor is used as I cannot enclose the above code in <script type="text/sjs"> tag.
How can I get this working in AngularJS
The library you linked says you need to include this on the main page:
<script type="text/sjs">
// Your SJS code here!
</script>
Make sure you've labelled it that way. Most javascript is labelled as "text/javascript" (or has no label at all, in which case the <script> tag implies javascript.
The code you posted runs fine when typed in the command-line-like eval tool they have on the StratifiedJS page - likely there is nothing wrong with the code itself, just the way it's loaded.
As #blgt said, you need to put the SJS code inside an appropriate <script type="text/sjs"> tag (since most StratifiedJS code is not valid JavaScript).
In order to access SJS functions from plain JS frameworks like SJS, you could attach them to some well known object, e.g:
<script type="text/sjs">
window.myFunction = function() {
waitfor() {
AsyncService.getThisDone().then(function(result) {
// some more calculation
resume();
});
}
}
</script>
You can then call window.myFunction from any JS code. In real code you'd probably pick a more unique name ;)
Note: it's impossible to actually wait for the execution of a suspending StratifiedJS function like this if you call it from JS. So if you're calling StratifiedJS functions from JS, generally they should be fire-and-forget (i.e functions which are only executed for their side-effects, rather than functions which return a result).
This blog post has some details about integrating AngularJS and StratifiedJS, which may clarify the relation between them:
http://onilabs.com/blog/megazine
The short version is that your JavaScript syntax is invalid.
The medium version is that
functionCall() {
// stuff here
}
...is invalid. You'd need a ; after functionCall(), and if you had one, the block following it would have no purpose.
Given that your linked documentation suggests that it is valid, there must be some pre-processing step that turns the code described into valid JavaScript that you've skipped. So your code is being processed as normal JavaScript, in which this construct is not valid.
The solution is to ensure that this code is pre-processed and/or run in the right environment (I think it's by their Conductance server).
Related
I have a situation using system.js with an angular application where I need to be able to include specific System.import(f) statements on a per-page basis, but it was imperative that they all be included before angular finishes bootstrapping and loading up its module.
I spent a long time on this problem and eventually this is the workaround I devised;
in my config.js, I am doing this...
config.js
// .... configuration ... //
Promise.all([
System.import('jquery'),
System.import('angular'),
System.import('angular.ng'),
System.import('bootstrap')
]).then(function() {
$(document).on('angular', function() {
angular.bootstrap(document, ['module-name']); $('body').removeClass('cloak');
});
});
Then I have a css class named .cloak. I tried ng-cloak but found it wasn't doing the job (I suspect because I'm deferring the angular bootstrapping)
.cloak { visibility: hidden; }
then on my individual page, I use this sort of code to shoe-horn my page-specific imports and finalize the process.
<!-- Load SystemJS -->
<script src="assets/js/system.js"></script>
<script src="config.js"></script>
<script>
System.import('app/main').then(function (e) {
Promise.all([
System.import('app/controllers/index'),
System.import('app/controllers/read'),
System.import('app/controllers/edit/article'),
System.import('scripts/lib/init')
]).then(function (m) {
$(document).trigger('angular');
});
});
</script>
So that's the basic idea; I don't allow angular to finish wiring up its module until everything has been imported through system.js. At present, this seems to work fine.
My problem is that I'm not a very good programmer, nor am I very clever. This seems like an extremely standard, normal problem that comes with the way system.js is designed and it occurs to me that there has to be a better, built in solution that I'm missing or haven't found.
Has anyone else dealt with this before that can offer some advice?
The reason I need to defer the module wiring is because I've got various angular controllers and models and such and I don't want them all to load on every page. (I mean, trimming down the scripts to only the ones needed at the moment is one of the points of a module loader, aside dependency resolution).
Trying to use the ng-app directive was constantly causing trouble - as angular would try to load before everything was finished and loaded in, so it had trouble finding things like certain controllers and the like on certain pages.
The biggest reason I need an alternative is that this method doesn't work well for minifying typescript.
This is an extremely standard issue with ng-cloak in general. Perhaps a better way has come around, but pretty much since I started working with angular I've just defined ng-cloak in the header of my index.html file like this:
<style>
[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak {
display: none !important;
}
</style>
and added class="ng-cloak" to the body tag of my page. It works great and when Angular finishes loading it's internal ng-cloak styles effectively overwrite mine.
It seems like moving the inline script basically as is, to an external file, would still allow it to run exactly as you have it and then minification and such would be fine.
It also sounds like you're not creating a SPA here, since if I understand you correctly, you're calling config.jss from each page. You may want to reconsider that and go with a SPA. You will likely end up loading everything up front, but you'll load it all only once.
After a lot of research, and tinkering, I can't seem to actually get my Protractor test to do anything else other than have an Angular related error, even though I am using browser to avoid Angular being detected at all.
The test involves an Angular app, opening a dropdown in it, and clicking on the link for the console; the console opens a non-Angular admin page in a separate window.
So based on the many informative SO posts I found, I first used this...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
//expect for new window here
});
});
Which appeared to work, as I could get to the window through repl pretty easily.
The issue is when either of the following were added...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
One expect check the URL and the other checks for the header element on the page, which is a table header. When I run this, I get the following:
Error while waiting for Protractor to sync with the page: "angular could not be found on the window"
When I decide to use browser.ignoreSynchronization = true, both in the function, or in a beforeEach, with or without a following afterEach setting it to false, I get the following:
JavascriptError: angular is not defined
I can't seem to get any "useful" errors to help me debug it, and trying it in repl does not help, as I get the same issue.
To be comprehensive, trying my URL expect without getting the second window will give me the root, and the other will fail.
Just doing one or the other will cause the same problem.
Changing to regular syntax (element(by.css...)) does not change things.
So much for my first question...
It appears that my use of browser.getLocationAbsUrl() is meant to be used for an Angular page, and was causing my issue...
Essentially, even though I believed I was using pure Webdriver calls, that call still required Angular on the page to work...
As stated in another post, the use of browser.driver.getCurrentUrl() is a non-Angular call using Webdriver, and fixed the problem. Thus, the final code is the following...
browser.sleep(1000); //to wait for the page to load
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.driver.getCurrentUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
This works without setting ignoreSynchronization, BTW.
I realized it would probably be something relatively simple to fix it, just didn't expect I'd get it that quickly (I intended on submitting the question last night, but posted it this morning instead).
In any case, I hope this will at least be a good reference for anyone else facing the same issue.
Seems like getLocationAbsUrl is angular abs url.
Try using the native driver getCurrentUrl instead.
-- expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
++ expect(browser.driver.getCurrentUrl() ...
I have an AngularJS web application.
I'd like to use peg.js in my application.
I've just written a peg.js grammar: CriteriaValue.pegjs and generated the parser with the command line:
pegjs CriteriaValue.pegjs, which generated CriteriaValue.js.
Could someone explain to me how to use the parser ?
var result = parser.parse('my string'); doesn't work.
I've created a plunker:
http://plnkr.co/edit/Ae05SeZAjKOQ75B3lvLc?p=preview
Short Answer
In CriteriaValue.js, change module.exports in the first line to parser
In index.html, swap the <script> tags so that CriteriaValue.js comes first
(Optional) In script.js, output the results of your parse as a formatted JSON string, in order to see the actual values
Here's the plunker: http://plnkr.co/edit/kiBp2Na9s4PXpenCzQjx?p=preview
Long Answer
Run your original plunker and check the console logs; you'll notice 2 errors:
ReferenceError: Can't find variable: parser (script.js:3)
ReferenceError: Can't find variable: error (CriteriaValue.js:1)
The first error is due to the fact that no parser object is ever created in global scope, by script.js or by CriteriaValue.js.
Looking at CriteriaValue.js, you can see it's actually assigning the generated parser object to a non-existent modules.export. This is the default behavior of PEG.js, as it assumes you're going to use your parser with node.js. The reason you're seeing the error is that there is no module object, so we can't assign to this non-existent object's export property. Changing the assignment to parser, which is something we can assign to (because PEG.js doesn't use strict mode), avoids this error and makes parser available for use in script.js.
Finally, the parser needs to be created before script.js can use it; hence the reason for the <script> swap.
For future creation of CriteriaValue.js, do it like this:
pegjs --export-var parser CriteriaValue.pegjs
This will generate the file so that the object is assigned to the variable parser instead of module.exports.
Where AngularJS Comes In
As #dirkk said in the comments, defining the parser as a global variable is bad practice and certainly not the AngularJS way, which is to implement your parser as a service.
The quickest (but not necessarily best) way to do that is to take your already generated CriteriaValue.js code and wrap a service around it. e.g.:
angular.module('yourApp.services', [])
.factory('Parser', function() {
// The generated code, except replace "parser = " with "return "
});
Another option is to fetch the .pegjs file & generate your parser on the client using PEG.buildParser():
angular.module('yourApp.services', [])
.factory('Parser', ['$http', '$q', function($http, $q) {
var deferred = $q.defer();
$http.get('path/to/CriteriaValue.pegjs')
.success(function(grammar) {
try {
deferred.resolve(PEG.buildParser(grammar));
} catch (e) {
deferred.reject(e);
}
})
.error(function(message) {
deferred.reject('Unable to load grammar: ' + message);
});
return deferred.promise;
}]);
This makes updating your grammar easier, as you won't have to rewrite your service every time, but it adds a delay in loading your app. The feasibility of this depends on how complex your grammar is & how often it actually needs to change.
Despite how you build your parser, you don't necessarily need to expose the generated parser object directly to the rest of your Angular app. Instead, you can implement a higher-level API for what your app will actually do with this parser (e.g. validate(input), getAST(input), etc...). This way, if you decide in the future to switch to a different parser (e.g. Jison), you'll have much less code to change.
I make a project in worklight used dojo mobile 1.8.1 and angularjs 1.0.1,but i got a strange problem.
Here is my html part:
<div data-dojo-type="dojox.mobile.ScrollableView" data-dojo-props="selected:true" id="id1" ></div>
<div class="full" data-dojo-type="dojox.mobile.View" id="id2"></div>
and my JavaScript part:
require([
"dojo", "dijit/_base/manager","dojo/parser", "dijit/registry",
], function(dojo) {
dojo.ready(function() {
// dijit.byId("id1").performTransition("id2"); //////////place I
});
});
var angularApp = angular.module('app', [])
.run(['$rootScope','$templateCache','$route',
function($rootScope,$templateCache,$route) {
dijit.byId("id1").performTransition("id2");////////place II
}]);
The problem is at place I, it works well, but when I put "dijit.byId("id1")" at place II, it shows:
dijit.byId("").is not defined
The ready function is executed after dojo parsed your document & constructed the widgets you try to get using dijit.byId.
The second part is not placed within the ready function, so dojo can't find your elements yet !
Solution: Access your elements in the ready function OR do not declare them declaratively (like you did, using html code...) !
Lucian
The dojo.ready() function registers an event-handler function (callback) which will be fired after the DOM got completely parsed.
This comes in very handy if you want to be sure that every html element got rerendered as dojo-widget before you perform operations on them.
So, in your example, Code II will be executed before the dijit.byId() function has been made available by loading the necessary modules (dijit/registry, ...). Code II would only work after the dom-ready event got fired and your "dojo.ready()" function did load the required modules.
You should definately invest 5 minutes in reading what dojo.ready() is about:
http://dojotoolkit.org/reference-guide/1.8/dojo/ready.html
Sidenote:
You shouldn't use dijit.byId() any more in Dojo 1.8.1. Try using dijit.registry.byId() (you have to require the dijit/registry module).
http://dojotoolkit.org/reference-guide/1.8/dijit/registry.html#dijit-registry-byid
I am using Jquery 1.3.2 for a script that needs it to run in IE 7/8.
The following code I've made to modify tabSlideOUt v1.3
By William Paoli: http://wpaoli.building58.com is causing a conflict and throwing an "Invalid Argument" error in jquery.
<script type="text/javascript">
$(document).ready(function() {
$("div#slidetab_1.slide-out-div a.handle").click(function () {
$("div#slidetab_2.slide-out-div").toggleClass("slide-height", 250) ;
});
$("div#slidetab_2.slide-out-div a.handle").click(function () {
$("div#slidetab_2.slide-out-div.tab2.slide-height").toggleClass("slide-height");
});
});
</script>
It seems that the toggleClass function is causing the error. Does anyone know of another way to code this so I don't have to use toggle?
I'm sorry it seems so vague but I was having trouble posting an example on JS Fiddle.
All I need is an alternative method for toggleClass
Thanks in advance
Cheers
The problem is that you pass 250 as second argument... what is it supposed to do in your code?
From the documentation:
switch A Boolean (not just truthy/falsy) value to determine whether the class should be added or removed.
It seems to have no purpose so I suggest to remove it.
Update: After having a look at the jQuery source code, passing 250 should not throw that error. Nevertheless I suggest to remove it and test it. If it does not work, you have to provide more information (where exactly the error is thrown, etc.).
Alternatively, you use this function to toggle the class:
function toggleClass($element, cls) {
$element[$element.hasClass(cls) ? 'removeClass' : 'addClass'](cls);
}