Using Breeze with RequireJS, Angular is loaded - angularjs

Using TypeScript, AMD, "requirejs", "breeze" but not "angular", I just upgraded from Breeze 1.4.0 to 1.4.6. Now, when "breeze" is loaded, it also tries to load "angular" which fails with...
Module name "angular" has not been loaded yet for context: _.
Use require([]) http://requirejs.org/docs/errors.html#notloaded
The problem seems to result from Breeze executing the following line.
var ng = core.requireLib("angular");
What have I done wrong so this code is executed anyway? Why does Breeze think that Angular has to be loaded?
When replacing the above line with the following, anything works fine.
var ng = undefined;

I'm having trouble reproducing this.
True, due to a peculiarity in the Breeze code, Breeze will execute the following line even when angular is not present
var ng = core.requireLib("angular");
... and that will fail with
Module name "angular" has not been loaded yet for context
because it can't find a library called angular.js (I assume you don't have it)
But that failure occurs inside another function (__requireLibCore) within a try/catch
function __requireLibCore(libName) {
var lib;
try {
if (this.window) {
...
if (window.require) {
lib = window.require(libName);
}
if (lib) return lib;
}
} catch(e) {
}
return lib;
Are you seeing some other code path in which this error is thrown?
UPDATE 11 December 2013
Thanks, #mgs, for your email explaining how you saw the exception. I summarize for those who read this later.
Breeze started looking for AngularJS in v.1.4.6. To be perfectly clear, Breeze does not need angular; it just wants to know if angular is available. Breeze doesn’t need knockout, jQuery or Q either. But under varying circumstances it may look for these libraries and use them if it finds them.
AFAIK there is no other way in requireJS to detect if a module has been loaded then to call require("angular"). Unfortunately, require("angular") throws an exception when it can't find that module.
Breeze itself does not fail because that call is caught in a try/catch. Many (most?) devs will never see this exception.
But #mgs has attached a requirejs.onError event handler ... which I hasten to add is a good practice. Of course his handler will see the "angular not found" exception even though Breeze caught it and moved on. He writes:
That “requirejs.onError” function is called, when Breeze tries to load Angular. In the real program this causes an entry into the log, and alarm bells are ringing. It was this entry that made me ask the question on StackOverflow.
What to do? I don't think Breeze can do anything unless someone knows a way to detect a loaded module without triggering the requirejs.onError event. I think it is up to the developer to compensate.
I recommend teaching your handler to ignore Breeze's attempt to find angular. Don't sound the "alarm bell" for this particular failure.
Alternatively, you could define a dummy module, as #mgs, did so that require finds an "angular" module. I'm not fond of this approach because it fools Breeze into believing that Angular is available and Breeze might act on that misunderstanding in the future. It's harmless today but who knows about tomorrow.
In any event, the mystery has been explained and suitable workarounds are now known. Thanks, #mgs, for the opportunity to explore this subject.
UPDATE 12 December 2013
We just released Breeze v.1.4.7 which includes the change you recommended ... using require.defined to check first if a module is loaded. Works like a charm.
I took the occasion to re-write the Todo-Require sample such that everything is loaded in a single require script line:
<!-- Require + main. All scripts retrieved async by requireJS -->
<script data-main="Scripts/app/main" src="Scripts/require.js"></script>
The documentation explains how it all works.
Thanks for your question and feedback.

you can force angularjs to be loaded by adding the following typescript line:
/// <amd-dependency path="angular"/>
alternatively you can make breeze depend on angular in your requirejs config.
Update In case you are not using angularjs you can safely exclude this file from your project : https://github.com/IdeaBlade/Breeze/blob/master/Breeze.Client/Scripts/IBlade/b00_breeze.ajax.angular.js

Related

babel-node error 'Reference error: window is not defined'

I was given the task to implement server-side rendering for a react application. I've followed the this tutorial: https://scotch.io/tutorials/react-on-the-server-for-beginners-build-a-universal-react-and-node-app and, afterwards, followed the exact steps on the actual application. Everything worked well with implementing the client-side rendering, but as soon as I continued with the server-side one, I got the following error: 'Reference error: window is not defined'
The problem is that the application uses scrollmagic, which is a client-side-only library (note: I added conditionals 'require' to any scrollmagic references in the code itself, but I can't find a way to bypass the module).
I thought about adding the scrollmagic library on the client-side, but as soon as I remove it I get an error from the 'require' statements.
I apologize if this is something obvious but I am new to JavaScript and have been searching for a couple of days and found nothing so far. If I can provide any additional information please let me know! Also, if you have any suggestions as to how I should handle this, I am all ears!
Best regards,
Andrew
The window object is a property of the browser/client, so you will not have access to it when executing javascript on the server. A library such as: https://www.npmjs.com/package/window-or-global can help, as well as adding conditional logic to check for the window object before executing code that depends on it.
In addition to the suggestion by #sconway to manually check for the presence of window when calling these client-side methods another method I have used in the past is to put that code in componentDidUpdate life-cycle method.
This method is guaranteed to not be called on the server, only on the client.

Can SystemJS plugins modify already transpiled files?

While attempting to get Angular (1.x) working with systemjs I realized that there is not currently the capability (that I know of) to automatically insert $inject into angular components, which keeps the components working even when the arguments to the functions are mangled by the minifier. Manually creating the $inject annotations is tedious, error-prone and violates the DRY principal.
There is a mature npm module called ng-annotate which solves this problem and is used in many similar situations for bundling. As I've been exploring SystemJS, I see that there is a plugin system that includes the ability to translate source code, which is exactly what ng-annotate does.
From what I can see, though, SystemJS only gives you the ability to map a particular file extension to a single loader and all the examples of the plugins are to support a new file type. What I would like to do is post-process the output of SystemJS's transpilation process rather than add a new file type. It seems like SystemJS should be able to do this since it has a processing pipeline, but I can't quite figure out how to hook into it the right way. Right now I am using Browserify to achieve the same effect, but I have ended up with a rather complex set of build tasks and I would like to simplify it with SystemJS if possible.
Other strategies to be able to use ng-annotate in the loader pipeline with SystemJS would be appreciated too.
Eventually I figured out a way, but this feels really clunky. System.src itself uses a hook() function to do this, but it's not exported for use. I'd be grateful for any ways to improve this and I hope eventually a properly supported mechanism for chaining loader functionality becomes available:
var System = require('systemjs');
var systemTranslate = System.translate;
System.translate = function(load) {
return systemTranslate.call(this, load).then(function (result) {
if (result) {
var processedResult = result; // Do your processing here.
load.source = processedResult;
}
return load.source;
});
}
I haven't experimented much with this, since my particular use cases for System.js building is currently a dead-end (Typescript source-maps are still busted), but presumably you can also return a promise.
I'll leave this answer un-chosen for a while to see if anybody has some better advice.

Dynamically override angular service?

Use case:
I'm writing system tests using Geb/Selenium (so outside of angular).
I want to decorate $http to log all requests/responses at run time.
and here's the catch: without touching the source code.
Before you rush to answer "use $provide#decorator", for example,
http://blog.xebia.com/2014/08/08/extending-angularjs-services-with-the-decorate-method/
That solution for this use case means adding a test hook into production code... that's normally a bad thing I want to avoid if possible.
Update: Geb allows you to run Javascript in the browser window. So just for the heck of it I ran the tutorial code to decorate $http. Unfortunately, it didn't work because apparently you can't re-config the app after it's been loaded. But even if it did work, this brings up another interesting point---I need to override $http before any modules have had a chance to use it.
Since decorating $http service would be the cleanest way of doing this, you can avoid polluting production code by using something like ng-constants and gulp/grunt to only add decoration code for a 'test' environment.
See related Q/A here: How do I configure different environments in Angular.js?
If you are inclined on changing this at runtime(where runtime takes place in a test environment), you may need to go 'closer to the metal' and deal with XMLHttpRequests: Add a "hook" to all AJAX requests on a page

Testing RequireJS application with FluentAutomation?

I'm attempting to write some UI tests for a RequireJS-based Backbone application, utilizing FluentAutomation.SeleniumWebDriver and NUnit. The HTML page in question contains a typical data-main attribute for loading the RequireJS module for the application. My struggle is in properly detecting when the application is fully loaded with these tools; the only thing I've gotten to work consistently so far is using an explicit wait in seconds, like so:
I.Open("http://myapp")
.Wait(5)
.Enter("foo").In("input[name=username]")
.Enter("bar").In("input[name=password]")
.Click("button")
.Wait(5)
.Expect.Text("Welcome").In("#welcome");
This is less than ideal -- my test as written above will always take at least 10 seconds to run, when in reality the app might be "ready" much faster than that. What I'd like to be able to do is something like this:
I.Open("http://myapp")
.WaitUntil(() => I.Assert.Exists("input[name=username]"))
.Enter("foo").In("input[name=username]")
.Enter("bar").In("input[name=password]")
.Click("button")
.WaitUntil(() => I.Assert.Exists("#welcome"))
.Expect.Text("Welcome").In("#welcome");
However, this doesn't work -- using WaitUntil here actually seems to prevent the app from loading, for reasons unclear to me, as I simply receive timeout exceptions after the default wait period (30 seconds), stating that it was unable to locate the element in question within that timeframe.
I see that Selenium 2 provides a WebDriverWait for this kind of scenario, and possibly that would work here, but am unsure how I would use this within FluentAutomation (and a quick search of the FluentAutomation code on GitHub doesn't seem to indicate it's in use within the library).
What can I use in FluentAutomation to properly wait for a RequireJS module (or DOM loaded by it) to be ready?
Additional details:
This might not be a RequireJS compatibility problem at all. I've looked further into the app and found that what's happening after the Click("button") is actually a window.location.replace -- not a RequireJS async module load. It's the one place in the app that this is occurring, apparently. So, is a window.location redirect a known scenario that would cause problems with WaitUntil, and is there an alternate approach (aside from a simple Wait(5)) that would properly handle this?

AngularJS constructor or init?

All,
We are developing our app with AngularJS and time and again we keep running into the issue of Angular running or loading controllers twice. This becomes a little more intrusive when testing our controllers and more specifically when working with Testacular with jasmine's SpyOn's (since they get triggered before our code runs). So, our question is, is there such a thing as a constructor or init method that Angular is guaranteed to call when instantiating the controllers w/o having to hack work-arounds in the test code? TIA.
If you are specifying the controller in your router, then your template doesn't need to specify the controller via an ng-controller tag. Doing so will double load your controller.
Your controllers shouldn't be loaded twice, unless you are doing something wrong. You shouldn't have to hack any work-arounds.
You might want to provide a concrete example of how you are loading the controllers (and/or the partials which are associated with the controllers). It sounds like you probably have a routing issue which is causing your view to be loaded twice for each request.
Assuming that is a routing-related issue, unless/until you can provide more information to help people to help you, you may want to read this document. Pay particular mention to sections that mention 'redirect' and 'HTML 5' mode:
http://docs.angularjs.org/guide/dev_guide.services.$location
With so little information to go on, I can't answer your question, but perhaps that link will help you to help yourself. :)

Resources