Angular, services, and module dependency confusion - javascript

I'm starting out with Angular and am running in to problems. I'm not sure I am understanding how module dependencies work.
When creating a module, you pass in an array of required modules (that contain services), right? And when you actually use a controller in that module, you pass it a service function defined in one of your required modules.
This is the error I am encountering in my application:
Failed to instantiate module MyApp due to:
Error: [$injector:modulerr]
Here is my HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>MyApp</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="css/foundation.min.css">
<link rel="stylesheet" href="css/main.css">
</head>
<body data-ng-app="MyApp">
<div data-ng-controller="MyAppCtrl">
<div class="three columns">
<h1 id="logo">LOGO</h1>
</div>
<div class="nine columns">
<div id="settings-nav" class="row">
<select class="three columns">
<option value="settings">My Settings</option>
<option value="users">Add/Edit Users</option>
<option value="account">Account Settings</option>
</select>
</div>
<div class="row">
<nav id="main-nav">
<ul class="six columns">
<li><a id="machines-link" class="button" href="/machines">Machines</a></li>
<li><a id="customers-link" class="button" href="/customers">Customers</a></li>
<li><a id="inspections-link" class="button" href="/inspections">Inspections</a></li>
</ul>
<div class="three columns">
<form id="search">
<input type="text" placeholder="search" />
</form>
</div>
</nav>
</div>
<div data-ng-view id="template-wrapper"></div>
</div>
</div>
<!-- required libraries. -->
<script src="js/vendor/angular.min.js"></script>
<script src="js/vendor/angular-route.min.js"></script>
<script src="js/vendor/angular-animate.min.js"></script>
<script src="js/vendor/angular-resource.min.js"></script>
<script src="js/vendor/underscore.min.js"></script>
<!-- services for each controller. each are under their own module. these talk to the rest server. -->
<script src="js/services/customer.js"></script>
<script src="js/services/inspection.js"></script>
<script src="js/services/machine.js"></script>
<!-- sets up the main MyApp module and dependencies. -->
<script src="js/setup.js"></script>
<!-- controllers for each view. all are under the MyApp module. these are loaded automatically with angular's routing. -->
<script src="js/controllers/customers-list.js"></script>
<script src="js/controllers/inspections-list.js"></script>
<script src="js/controllers/machines-list.js"></script>
<script src="js/controllers/customer.js"></script>
<script src="js/controllers/inspection.js"></script>
<script src="js/controllers/machine.js"></script>
<!-- routing config and main modustri controller. -->
<script src="js/routing.js"></script>
<script src="js/controllers/MyApp.js"></script>
</body>
</html>
I define my service modules like this:
var MachineServices = angular.module('MachineServices', ['http']);
MachineServices.factory('Rest', function($http){
return{
//get machine from server
//save machine to server
//delete machine from server
//get machine list from server
}
});
In setup.js, after the modules with services are loaded, I create my main module:
var MyApp = angular.module('MyApp', ['ngRoute', 'ngAnimate', 'CustomerServices', 'InspectionServices', 'MachineServices']);
There is something wrong with the way these modules and their containing services are created. When I remove them as dependencies I no longer get an error.
What am I missing here?
Thanks in advance.

I think your problem is likely within your module definition:
var MachineServices = angular.module('MachineServices', ['http']);
You don't need to depend upon http. The $http service is part of the Angular core, so it is not a module you need to import. Doing so will give you an error.
I should also correct you on your use of "Services" and "Modules" interchangeably. A module is a collection of factories, services, directives, controllers, filters, etc that can be injected into other modules to use. "Service" has a specific meaning in Angular and is more granular than "Module".

Related

Console log not showing simple $scope

My console is not showing a simple log from below angular code.
I am getting a 304 Not Modified error in Firefox.
My HTML has the myApp and mainController defined and used.
var myApp = angular.module('myApp', []);
myApp.controller('mainController', function($scope) {
$scope.name = 'Name';
console.log($scope.name);
});
Any ideas what is going on here?
Edit - here is the HTML code:
<!DOCTYPE html>
<html lang="en-us" ng-app="myApp">
<head>
<title>Learn and Understand AngularJS</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta charset="UTF-8">
<!-- load bootstrap and fontawesome via CDN -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<style>
html, body, input, select, textarea
{
font-size: 1.05em;
}
</style>
<!-- load angular via CDN -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<header>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">AngularJS</a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><i class="fa fa-home"></i> Home</li>
</ul>
</div>
</nav>
</header>
<div class="container">
<div ng-controller="mainController">
<h1>Hello world!</h1>
</div>
</div>
</body>
</html>
Has your console.log statement always been in your code? Or have you just added it?
If it's the former, then I'm not sure what's happening. Sorry.
If it's the latter, then it sounds like Firefox is loading a cached version of your file that doesn't include your console.log statement. In fact a response with a HTTP status code of 304 Not Modified isn't an error. It is the server telling the browser that the requested resource hasn't changed, so you can load your cached copy.
Try clearing Firefox's cache, or reloading using Ctrl + shift + R or Cmd + shift + R to override the files in the cache.

ng-include use for header / footer

New to angular.js I want to use ng-include for header and footer that are common to many pages of my site for easier update
I developped a small very basic example (basic.html) to test this but this is not working
<html ng-app>
<head>
<title>Basic Angular.js</title>
<script src="angular.min.js"></script>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<hr>
<h1>Hello {{yourName}}!</h1>
</div>
<div ng-include="'myFile.html'"> Inclusion 1</div>
<div ng-include src="'myFile.html'"> Inclusion 2</div>
</body>
</html>
Myfile.html is as follow
<div>
<h1> Footer example </h1>
</div>
All files : basic.html, myFile.html and angular.min.js are in the same root directory (that was an issue in other posts related to ng-include errors)
While the first part of the basic.html is working fine (name input and dynamic display with angular) the ng-include is not working in both syntaxes:
<div ng-include="'myFile.html'">...
or
<div ng-include src="'myFile.html'"> ...
I did not miss the two consecutive quotes " and ' that were an issue in other posts related to ng-include errors.
I'm at a loss to understand what is the correct syntax or what is missing
Make sure you have angular.module and angular.controller defined. ng-include won't work without them being defined. I hope it helped.
Your code should look like this, note that ng-app="myApp":
(function(angular){
// create the module and register it to angular
var app = angular.module('myApp', []);
app.controller("maincontroller", ["$scope"]);
}(angular));
<html ng-app="myApp">
<head>
<title>Basic Angular.js</title>
<!--I'm using the cdn for demo purpose-->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<hr>
<h1>Hello {{yourName}}!</h1>
</div>
<!--both of these syntax should work-->
<div ng-include="'myFile.html'"> Inclusion 1</div>
<div ng-include src="'myFile.html'"> Inclusion 2</div>
</body>
</html>

Initiating AngularJS

I'm having an issue getting started with AngularJS. I have downloaded the minified file and have it living in a JS directory along with a app.js file. Everything works until I try calling the app.js file. Then it breaks. Here's my code.
index.html
<head>
<meta charset=utf-8 />
<meta name="description" content="description">
<title>My App</title>
<script src="js/angular.min.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app>
<h1>Intro to Data Binding</h1>
<div ng-controller="DBController">
<input type="text" ng-model="userName" />
<p>Hello, {{userName}}.</p>
</div>
</body>
app.js
function DBController($scope) {
$scope.userName;
}
on your body tag do ng-app="app"
then, in your .js file...
angular.module('app', [])
.controller("DBController", function($scope){
$scope.userName = "My Name";
})
It also might be helpful to get a basic understanding of angular
the angular team provides a lot of useful videos and other resources
https://docs.angularjs.org/misc/started
Free Video Tutorials: https://www.codeschool.com/courses/shaping-up-with-angular-js

<head> JS scripts are not executing

I'm using JQuery Mobile, and now I would like to navigate through pages with the minimum of loading amount of scripts everytime a page is being loaded, I mean that I would like to import only ONCE all the general scripts of all the pages (JQuery.js, jquery_mobile.js, main.js etc...) and
So I have an index.html with the following code :
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0">
<title>Hybrid App</title>
<link rel="stylesheet" href="jqueryMobile/jquery.mobile-1.4.4.css" />
<link rel="stylesheet" href="jqueryMobile/jquery.mobile.icons-1.4.4.css" />
<link rel="stylesheet" href="css/jquery.mmenu.css" />
<link rel="stylesheet" href="css/main.css" />
<script>window.$ = window.jQuery = WLJQ;</script>
<script type="text/javascript" src="js/jquery-2.1.1.js"></script>
<script type="text/javascript" src="jqueryMobile/jquery.mobile-1.4.4.js"></script>
<script type="text/javascript" src="js/jquery.mmenu.min.js"></script>
<script type="text/javascript" src="js/initOptions.js"></script>
<script type="text/javascript" src="sharedResources/customersObject.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript" src="js/messages.js"></script>
</head>
<body style="display: none;">
<div data-role="page" id="page">
<link rel="stylesheet" href="css/pages/splash-view.css" />
<div data-role="header" id="header" data-position="fixed"></div>
<div data-role="content" id="pageContent">
<div id="splash-wrapper">
<div class="splash-content">
Login
</div>
</div>
</div>
<div data-role="footer" id="footer" data-position="fixed"></div>
<nav id="menu">
<ul data-role="listview" data-inset="true">
<!-- list of items in the slide sidebar menu (called drawer menu in Andorid -->
</ul>
</nav>
<script src="js/pages/splash-view.js"></script>
</div>
</body>
so when clicking on the link I go to an external HTML file located in : pages/faqs-view.html with the following code :
<div data-role="page" id="page" data-url="pages/faqs-view.html">
<link rel="stylesheet" href="css/pages/faqs-view.css">
<div data-role="header" id="header" data-position="fixed"></div>
<div data-role="content" id="pageContent">
<div id="faqs-wrapper">
<div class="faqs-content">
<div data-role="collapsible-set" data-corners="false" data-collapsed-icon="arrow-r" data-expanded-icon="arrow-d" id="faq-set">
</div>
</div>
</div>
</div>
<div data-role="footer" id="footer" data-position="fixed"></div>
<nav id="menu">
<p class="employee-name">Welcome, Ali</p>
<ul data-role="listview" data-inset="true">
<!-- list of items in the slide sidebar menu (called drawer menu in Andorid -->
</ul>
</nav>
<script src="js/pages/faqs-view.js"></script>
The problem is that when loading the faqs-view.html page, I can see that none of the scripts included in the <head> are being executed, I have tried to put them after the <body> tag, but it's the same, BUT the CSS files are being interpreted.
How can I achieve that ? Thank you.
Worklight-based applications are Single Page Applications. This means you should never navigate away from the index.html. Doing so will cause the app to lose its context to the Worklight framework, thus it will begin to fail.
If you'd like to add multi-page navigation to the application, you can do so using the API provided by 3rd-party frameworks. Here you are using jQuery Mobile.
You've changed the loading order of scripts. You shouldn't.
Use the Worklight Studio wizard in order to create an app template with jQuery Mobile (new project > new hybrid application (click on "configure javascript libraries" > select the library you would like to add))
Keep initOptions.js, main.js and messages.js where they are by default, at the bottom
The index.html you get is your template with jQuery Mobile
If you want to replace the bundled jQuery, you need to comment out (slide #6) the following script tag: <script>window.$ = window.jQuery = WLJQ;</script>. Worklight is bundled with jQuery 1.9.x.
For a bare-bones example of multi-page navigation in a Worklight-based application, using jQuery Mobile, take a look at this project.
As you navigate between pages, you only replace the contents of the data-role="page". The scripts have already been loaded. You can load additional scripts per where required when loading a specific page.
They are executed in the order you put them on the page.
window.$ = window.jQuery = WLJQ;
Cannot be executed before jQuery is included.
Edit:
When you load a new page without the header it's clear that it won't be excecuted because it is not there.
When you replace html in your page you should look at the "on" function for events.

deviceTheme.js and dojo.js can not be loaded in Chrome

I am following dojo mobile tutorial for Part 2 - Developing a Dojo Mobile Application: FlickrView.
But when I tried examples in that tutorial, I found that //ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojox/mobile/deviceTheme.js and //ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js can not be loaded in my test html below, these two js file loaded successfully in demo page
Am I do something wrong?
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<!-- prevent cache -->
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="pragma" content="no-cache">
<title>Dojo Mobile tutorial | Flickrview | Part II | HTML Structure</title>
<!-- application stylesheet -->
<link rel="stylesheet" type="text/css" href="css/flickrview.css">
<!-- dynamically apply native visual theme according to the browser user agent -->
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojox/mobile/deviceTheme.js"></script>
<!-- dojo configuration options -->
<script type="text/javascript">
dojoConfig = {
async : true,
baseUrl : './',
parseOnLoad : false,
mblHideAddressBar : true,
packages : [{
name : "flickrview",
location : "js"
}]
};
</script>
<!-- dojo bootstrap -->
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js"></script>
<!-- dojo application code -->
<script>
// Load the widget parser and mobile base
require(["dojox/mobile/parser", "dojox/mobile/compat", "dojo/domReady!"], function(parser) {
// Parse the page for widgets
parser.parse();
});
</script>
</head>
<body>
<!-- Feed view -->
<div id="feed" data-dojo-type="dojox/mobile/ScrollableView" data-dojo-props="selected: true">
<div id="feedHeading"
data-dojo-type="dojox/mobile/Heading"
data-dojo-props="fixed: 'top', label: 'Feeds'">
<span data-dojo-type="dojox/mobile/ToolBarButton"
data-dojo-props="icon: 'images/settings.png', moveTo:'settings', transitionDir:'-1', transition:'none'"
style="float:left;"></span>
<span id="refreshButton" data-dojo-type="dojox/mobile/ToolBarButton"
data-dojo-props="icon: 'images/refresh.png'"
style="float:right;"></span>
</div>
<div id="feedList" data-dojo-type="dojox/mobile/EdgeToEdgeList">
<div data-dojo-type="dojox/mobile/ListItem"
data-dojo-props="moveTo:'details', transition:'slide'" class="photoListItem">
<img src="images/photo1.png" width="80px" height="80px" alt="Title" style="float:left;"/>
<div class="photoSummary">
<div class="photoTitle">
Photo title here
</div>
<div class="publishedTime" data-dojo-time="2013-12-13">
published date here
</div>
<div class="author">
author here
</div>
</div>
<div class="summaryClear"></div>
</div>
<div data-dojo-type="dojox/mobile/ListItem"
data-dojo-props="moveTo:'details', transition:'slide'" class="photoListItem">
<img src="images/photo2.png" width="80px" height="80px" alt="Title" style="float:left;"/>
<div class="photoSummary">
<div class="photoTitle">
Another photo title here
</div>
<div class="publishedTime" data-dojo-time="2013-12-13">
published date here
</div>
<div class="author">
author here
</div>
</div>
<div class="summaryClear"></div>
</div>
</div>
</div>
</body>
</html>
Here's error message in Chrome.
To use the protocol-less version of the url (like //ajax.googleapis.com) you have to host your project somewhere (either on a local or a remote webserver).
You can not just open the file (using the file:// prefixed URL), because then it won't be able to find the specified libraries. What actually happens if you load such a URL is that the same protocol-prefix is used to load these pages. If you load a page just by opening the file, it will have a file:// prefix and not http:// or https://.
This is also the reason why it is working on the demo page (because it is hosted) and why you get these GET errors, it's trying to find ajax.googleapis.com on your local machine (due to the file:// protocol), which it obviously can't find.
To fix it you just use the full URL, for example:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js"></script>
Or a better solution is to put your project on a webserver (nginx, apache2, ...), because I don't think you will be able to load asynchronous modules either.

Categories