fter including require tag the application is behaving abnormal way .is there any way i can bootstrap my application apart from below code .
main.js
require(['/module.js'], function() {
angular.element(document).ready(function () {
angular.bootstrap(document, ['myApp']);
});
});
When I written as single file js file the code is working properly.
module.js
var name = 'myApp';
angular.module(name, [])
.controller('Controller', require(['controller.js']))
.factory('Service', require(['service.js']))
.filter('Number', require(['filter.js']));
I have included my main.js in index.html . index html has 3 views i am displaying them based on ng-show from index.html.
The problem is module.js loading properly and js files too. Script is not executing properly so that my entire index.html page including 3 views displayed automatically with error messages.
Control is not going to controller.js/service.js
Error :
Error: Unknown provider: depsProvider <- deps .
Did i miss any define code? Thanks in advance
Angular does not support AMD by default, You need to config angular to export angular object. Please check out the this post for more details.
require.config({
paths: {
'angular': '../lib/angular/angular'
},
shim: {
'angular': {
exports: 'angular'
}
}
});
Your module.js should be defined with define method of requirejs and it should return module.
You can omit file extesion (.js) while using requireJs
Related
Maybe I have fundamentally misunderstood how requirejs config works but I thought my configuration below made some libraries global so I could just use them in other files while only having to require and define files that I needed to use within the individual script. However I cannot reference $ (jQuery) in my application code without getting a reference error indicating it is not globally accessible. I've isolated the problem to the simple example below.
My file set up is as follows:
test
|
|-index.html
|-TestApp.js
|-MainApp.js
|-lib
| |-require.js
| |-jquery.js
| |-loadash.js
| |-backbone.js
|-css
|-test.css
The library file versions are RequireJS 2.1.22, jQuery 2.0.3, Loadash 3.10.1 and Backbone 1.2.1. I'm just trying to set up my environment and the approach I am taking is to pass my TestApp.js file to require.js to load the required files and bootstrap the application code in MainApp.js. The script in index.html is as follows:
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' type='text/css' href='css/test.css'/>
</head>
<body>
<div></div>
<script src="./lib/require.js" type="text/javascript" data-main="./TestApp.js"></script>
</body>
</html>
The referenced css script file simply ensured the div is visible as an orange square. See below:
div {
height: 100px;
width: 100px;
background-color: #FA6900;
border-radius: 5px;
}
It's the script line in index.html that then kicks off the application code by passing my configuration file to requirejs. This is the TestApp.js passed across as data-main. The TestApp.js is here:
require.config({
paths: {
'jquery': 'lib/jquery',
'lodash': 'lib/lodash',
'backbone': 'lib/backbone'
},
map: {
'*': {
// Backbone requires underscore. This forces requireJS to load lodash instead:
'underscore': 'lodash'
}
},
shim: {
jquery: {exports: '$'},
underscore: {
deps: ['jquery'],
exports: '_'
},
backbone: {
deps: ['underscore'],
exports: 'Backbone'
},
TestApp: {
deps: ['backbone'],
exports: 'TestApp'
}
}
});
require(['MainApp'], function(MainApp) {
MainApp.run();
});
The file above references the paths to the library files I want to use, I then remap loadash to be loaded when underscore is required (I need some of the extra loadash capability), I then use the shim to ensure the dependancies are correct as the files are loaded. Passing this config file to require.js in the index.html seems to be working as all of the files are showing as loaded in my browser. However the problem seems to be they do not appear to be globally accessible as I thought they would be.
Following the config section the last require call loads the MainApp.js file and calls the exposed run function. The MainApp.js looks like this:
define(function(require) {
var run = function() {
$(document).ready(function() {
$('div').click(function() {
$('div').fadeOut('slow');
});
});
};
return {
run: run
};
});
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code. This is where I have misunderstood what is going on or have missed a step out. The exposed run function is being called but the first line that calls $ throws the error:
ReferenceError: Can't find variable: $
So my questions are:
What have I got wrong in my thinking?
(or) What am I doing incorrectly?
What should I be doing in order to preload and make available
frequently referenced libraries so that I do not need to require and
define them in every file I have?
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code.
You misunderstood how RequireJS works. You should read the documentation from start to finish. For now, here are things you should change.
You should require jquery in your MainApp module:
define(function(require) {
var $ = require("jquery");
You should remove your shims that you have for jquery, underscore and backbone as they all call define and shim is only for code that does not call define. I don't know what TestApp is but if it is your own code, you really should make it into a proper AMD module and remove the shim.
#Louis has made me realise the error in what I was doing above. Changing the shim in TestApp.js so that is reads:
MainApp: {
deps: ['backbone'],
exports: 'MainApp'
}
Corrected the problem, now Backbone, $ and _ are all available to the rest of my application code without cluttering up each files require. i.e. I do not need to begin every file with:
define (['lib/jquery', 'lib/loadash', 'lib/backbone'], function($, _ , Backbone) {
Given in my actual app the list of common deps is quite large this means I only need to define locally used resources and can control the paths from a single location.
How can I call requireJS require(['app'], function() {}); only once at the beginning for the whole application so that any subsequent require(["..."], function(...){}); don't need to be wrapped within require(['app']?
This is my set up:
1) Load require.js
<script data-main="js/app.js" src="requirejs/require.min.js"></script>
2) Have app.js shims and basUrl configured properly.
requirejs.config({
baseUrl: "scripts/js",
paths: {
"jquery": "../bower_components/jquery/dist/jquery.min",
"modernizr": "../bower_components/modernizr/modernizr",
.
.
.
},
shim: {
"jquery.migrate": ['jquery'],
.
.
.
}
});
3) Dynamically load JS on different pages:
// Home Page
require(['app'], function() {
require(["jquery", "foundation", "foundation.reveal"], function ($, foundation, reveal){
$(document).foundation();
});
});
// Catalog Page
require(['app'], function() {
require(["jquery", "lnav/LeftNavCtrl","controllers/ProductCtrl", "controllers/TabsCtrl"], function ($, NavCtrl, ProductCtrl, TabsCtrl){
$(function() {
NavCtrl.initLeftNav();
});
});
});
Unless I wrap with require(['app'], function()) each time I call require("...") to load external JS or AMD modules, the app is not initialized and I get JavaScript errors. The above code works but it's not very efficient.
Is there a way to start my requireJS app before I try loading scripts?
I tried calling at the very beginning right after I load require.min.js:
require(["app"], function (app) {
app.run();
});
but it didn't work.
There are no provisions in RequireJS to ensure that a specific module is always loaded before any other module is loaded, other than having your first module load the rest. What you are trying to do is share your first module among multiple pages so it cannot perform the work of loading what is specific to each page.
One way you can work around this is simply to load app.js with a regular script element:
<script src="requirejs/require.min.js"></script>
<script src="js/app.js"></script>
Then the next script element can start your application without requiring app.js:
<script>
require(["jquery", "foundation", "foundation.reveal"], function ($, foundation, reveal){
$(document).foundation();
});
</script>
This is actually how I've decided to launch my modules in the applications I'm working on right now. True, it is not as optimized as it could be because of the extra network round-trip, but in the case of the applications I'm working on, they are still in very heavy development, and I prefer to leave this optimization for later.
Note that generally you don't want to use script to load RequireJS modules but your app.js is not a real module as it does not call define, so this is okay.
Another option would be to use a building tool like Grunt, Gulp, Make or something else and create one app.js per page and have each page load its own app.js file. This file would contain the configuration and the first require call to load the modules specific to your page.
I am experimenting and trying to use the angular.element (jQuery wrapper) inside angular's config() function. However, in the main.js file, as soon as I add the deps under angular, it generates the $injector:modulerr error (where the 1st comment is)
Script tag is placed right before in my html file
<script src="js/vendor/require.min.js" data-main="js/own/main.js"></script>
main.js file
require.config({
baseUrl: "js/vendor/",
paths: {
"jquery": "jquery-2.1.1.min",
"angular": "angular.1.2.9.min"
},
shim: {
"angular": {
deps: ["jquery"], // As soon as I add this, it generates a $injector:modulerr error
exports: "angular"
}
}
});
require(["angular"], function(angular){
angular
.module("app", []) // ng-app="app" already defined in <body>
.controller("appctrl", function($scope){ // ng-controller="appctrl" already defined in <body>
$scope.sample = 1; // this works fine if I don't add deps under angular in require.config
});
});
Error is gone by removing the directive "ng-app='urAppName'" in the html page. The ng-app has to be manually bootstrapped by angular.bootstrap(document.body, ["urAppName"]) AFTER you define your angular module, e.g. angular.module("urAppName", []).controller().....;
Note that you can leave other directives such as ng-controller or your model data such as {{modelName}} in the page.
There is something really weird going on when I'm using RequireJS with AngularJS. I managed to load all my angular dependencies through RequireJS. I can see those scripts downloaded when I open up the Sources pane in Chrome's developer tool. But Angular keeps throwing an error in the console that it failed to instantiate the module:
Uncaught Error: [$injector:modulerr] Failed to instantiate module MyTestApp due to:
Error: [$injector:nomod] Module 'MyTestApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure...<omitted>...0)
It seems like Angular, when loaded with RequireJS, cannot bind with the ng-app tag in the HTML page. I'm not sure if this is the case but it seems like so to me because when I import angular.min.js manually into the HTML page, it all works fine.
Did I do anything wrong when using RequireJS with Angular? How should I use the two together? Here's how my code look:
index.html
<!doctype html>
<html lang="en" ng-app="MyTestApp">
<head>
<meta charset="utf-8">
<title>AngularJS</title>
<link rel="stylesheet" href="css/style.css"/>
<script data-main="main" src="js/require.js"></script>
</head>
<body>
<div ng-controller="TestController">{{helloMessage}}</div>
</body>
</html>
main.js
require.config({
baseUrl: "scripts/app",
shim: {
"angular": {
exports: "angular"
},
"angular.route": {
deps: ["angular"]
},
"bootstrapper": {
deps: ["angular", "angular.route"]
},
},
paths: {
"angular": "../angular",
"angular.route": "../angular-route",
"bootstrapper": "bootstrapper"
}
});
require(["angular", "angular.route", "bootstrapper"],
(angular, ngRoute, bootstrapper) => {
bootstrapper.start();
}
);
bootstrapper.js
function run() {
app = angular.module("MyTestApp", ["ngRoute"]);
app.controller("TestController", TestController);
console.log(app); //Prints object to console correctly, ie, angular was loaded.
}
Here is how I would do it (DEMO).
In main.js, require angular, your app and maybe a controllers.js and other files:
require(['angular', 'app'], function (app) {
angular.element(document).ready(function () {
angular.bootstrap(document, ['MyTestApp']);
});
});
In app.js, require angular and angular route:
define(['angular', 'angular.route'], function() {
var app = angular.module("MyTestApp", ["ngRoute"]);
return app;
});
This is manual bootstraping and therefore does not need the ng-app tag at all.
I'm currently working on a pretty big application with angular and requirejs and I prefer to load the "big" libraries that are used by the whole app anyway independently from requirejs.
So I load one big file which includes angular, angular-route, requirejs, main.js in the beginning. Or if it makes sense to use a CDN version, load it from there. On the other hand I load every controller, directive, filter and service on request. I currently have 50+ controllers which allready makes a difference in initial load time.
But that all depends on the size of your app.
First you does not need to get a variable from the load of "angular.route". The module will be directly loaded in angular.
I think you should also wait for the dom ready event and also make a requirejs app module that will be in charge of loading all app dependencies:
app/app.js:
define([
"angular",
"angular-route",
"app/controllers",
"app/directives",
[...]
], function(angular){
var app = angular.module('app', [
"ngRoute",
"app.controllers",
"app.directives",
[...]
])
.config([function(){
// app configuration goes here
}]);
return app;
})
main.js
require(["angular", "app/app"],
function (angular, app){
angular.element(document).ready(function() {
angular.bootstrap(document, [app.name]);
});
}
);
In my project I want to use RequireJS and bootstrap my app as follows:
requirejs.config({
baseUrl: 'scripts/vendor',
paths: {
jquery: [
'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
'jquery'
],
angular: [
'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
'angular'
],
app: '../app'
}
});
require(['require', 'jquery', 'angular', 'app'], function(require, $, angular, app) {
console.log(require);
console.log($);
console.log(angular);
console.log(app);
});
On my index.html only RequireJS is loaded via script tag, where the RequireJS loads the above code.
What works:
- in my Network monitor I can see that RequireJS, jQuery, Angular and app are loaded
- The console.log messages print correct for require, jQuery and app
The angular object is somehow undefined. But if I don't load it from CDN and use my local load, it works! The local file is a RequireJS wrapper that looks like this:
define(['/components/angular/angular.min.js'], function () {
return angular;
});
How do I get this work with Angular'S CDN? Or does this depend on support from Angular?
First, you are confusing "paths" with "shim"
Path is good, don't go for "shim" behavior. But, you need to make your "paths" proper:
paths: {
jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
// NOTE: angular is "plain JS" file
angular: 'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
app: '../app'
}
Then, you need to let go of the need to have something returned to you... Just "use the force, Luke" :) and expect the right globals to be there when you need them:
require(['jquery', 'app', 'angular'], function($, app, thisValueDoesNotMatter) {
// you don't need to wrap "require" Just use global
console.log(require);
console.log($);
console.log(app);
// note, angular is loaded as "plain JavaScript" - not an AMD module.
// it's ok. It returns "undefined" but we just don't care about its return value
// just use global version of angular, which will be loaded by this time.
// because you mentioned it in your dependencies list.
console.log(window.angular);
});