I have the following scenario that works perfectly in debug mode, but as soon as I run it in release mode the second function (details page) is never triggered - I can only assume it has to do with minification.
Perhaps my design is the problem, but with my limited knowledge of Angular I need some advise on this.
Scenario:
2 MVC pages (First a summary list, second a details page)
1 ng-app instance
1 module
2 controllers - 1 per page.
On the first page the angular values resolve correctly, but on the details page all I see is the "{{ form.logEntry.Message }}" text (only in Release mode). This renders correctly in debug mode.
In the MVC pages I initiate the controllers as follows:
Summary page: <div class="container-fluid" ng-controller="LogEntriesController as table">
Details page: <div class="container-fluid" ng-controller="LogEntryController as form">
The outline of the angular code is as follows:
(function() {
'use strict';
var logEntryApp = angular.module('magiclogs',[]);
logEntryApp.controller('LogEntriesController', LogEntriesController)
LogEntriesController.$inject = ['$scope','$filter','$http','$q','$timeout'];
logEntryApp.controller('LogEntryController', LogEntryController);
LogEntryController.$inject = ['$scope','$filter','$http','$q'];
function LogEntriesController($scope, $filter, $http, $q, $timeout)
{
....
};
function LogEntryController($scope, $filter, $http, $q)
{
....
};
})();
The browser console points to an Unknown Provider error:
https://docs.angularjs.org/error/$injector/unpr?p0=nProvider%20%3C-%20n
Any insights/corrections welcomed.
Related
I'm trying to get this fileuploader plugin working on a page (it's actually .cshtml, but hopefully that's not the source of the problem). I don't know how to debug angular references to find out what's missing.
The fileuploader does work in a different place in the app:
markup: Views\Shared_MasterClientLayout.cshtml
<script src="#Html.GetContentPathAbsolute()/Content/lib/angular-file-upload/angular-file-upload.min.js"></script>
<body id="ng-app" ng-app="clientPortal"
controller: www\public\app\disabilities\disabilities.app.js
(function () {
'use strict';
var app = angular.module('disabilities', ['angularFileUpload']);
app.controller('disabilitiesController', ['$scope', '$rootScope', '$routeParams', '$fileUploader', disabilitiesController]);
function disabilitiesController($scope, $rootScope, $routeParams, $fileUploader) {
}
})();
But it does not work on my page:
markup: Views\Referral\ThankYou.cshtml
<script src="#Html.GetContentPathAbsolute()/Content/lib/angular-file-upload/angular-file-upload.min.js"></script>
<div id="ng-app" ng-app="cmorApp">
controller: ReferralContent\app\CreateReferral\cm.attachmentUploadCtrl.js
var AttachmentUploadCtrl = ['$scope', '$http', '$fileUploader',
function ($scope, $http, $fileUploader) {
I get
Uncaught Error: [$injector:unpr] Unknown provider: $fileUploaderProvider <- $fileUploader
I can see on the Sources tab in Dev tools that angular-file-upload-min.js has been loaded.
The worst part about this is a lack of consistency of implementation across pages that the various components are spread across. I know of no way to debug angular empirically.
I literally have no way to tell which of several apps is running, which controller is attached to a page and which is referring to what page.
Is there any way of inspecting a page and exposing what objects are loaded on it?
Can I write console.log(ng-app) and have it return 'cmorApp'?
Or console.log(app.controller) and have it return 'AttachmentUploadCtrl'?
I'm a noob to single page applications, Foundation for Apps (F4A), and Angular.js. This is the first time I've tried to add an Angular module to the framework and while it seems easy something isn't working. The problem is the Angular part of the html is displayed on the rendered page
{{ user.name || "empty" }}.
However, that isn't happening for the directives from F4A. They are not visible on the page. I haven't coded the controllers yet, just laying out the html. This module is for user inline editing of pages such as profiles so I don't have to have one profile page for data entry and another for display.
Help figuring this out would be deeply appreciated! Also, I could not find related guidance anywhere on the Web and I can't be the first person to screw this up.
I'm following the Getting Started instructions here.
1) The Bower installation went well and the module now lives in /bower-components/xeditable.
2) I've inserted the suggested css link in the index.html header.
3) I inserted the suggested js script in the header but also tried near the top of the Gulpfile where I think it should be:
// These files include Foundation for Apps and its dependencies
foundationJS: [
'bower_components/*', //add a bunch more like this.
//Angular-xeditable module
'bower_components/angular-xeditable/dist/js/xeditable.js'
],
4) This bit is already in Zurb's index.html at the top:
<html ng-app="app">
5) The instructions tell me to do this:
var app = angular.module("app", ["xeditable"]);
However, I put it at the top of app.js:
(function() {
'use strict';
angular.module('pfApp', [
'ui.router',
'ngAnimate',
//foundation
'foundation',
'foundation.dynamicRouting',
'foundation.dynamicRouting.animations',
//angular-xeditable directive
'xeditable'
])
6) Step 6 wants this code in a template so I put it in a template that already has Angular {{ }} that isn't causing a problem:
<div ng-controller="Ctrl">
{{ user.name || "empty" }}
</div>
7) Lastly, I copied this controller into app.js:
app.controller('Ctrl', function($scope) {
$scope.user = {
name: 'awesome user'
};
});
I found a coder on Upwork.com, Natalya Ivanyak, who got this to work. I've shown only the key parts as an example, not the whole form.
In projects-profile.html partial:
<form editable-form name="addProjectForm" novalidate ng-controller="projectFormCtrl">
<div class="small-12 columns">
<a href="" ng-click="$form.$show()" e-placeholder="Describe the project in one or two short paragraphs." editable-textarea="project.description" e-name="description" e-rows="40" e-cols="40">
<pre class="textarea-field">{{project.description || 'Describe the project in one or two short paragraphs.'}}</pre>
</a>
</div>
In controllers.js:
angular.module('pfApp').controller('projectFormCtrl', ['$scope', '$filter', function($scope, $filter) {
$scope.project = {
pitch: '',
description: '',
whatEverElseYouWant: ''
};
Hope this helps someone!!
I am experiencing some issues with implementing the angular-google-maps plugin (https://angular-ui.github.io/angular-google-maps/#!/) for the Ionic Framework software in that I cannot get the map to render at all. Crazy thing is that the GoogleMapAPI promise is being triggered (as per alerts that I am placing within there for testing purposes) but no map is rendered to the screen.
My index.html file (in my iOS directory) uses the following file calls:
_assets/_js/_plugins/lodash-2.4.1.min.js"
lib/ionic/js/ionic.bundle.js"
lib/ngCordova/ng-cordova.min.js"
cordova.js"
_assets/_js/_plugins/angular-google-maps-2.0.7.min.js"
_assets/_js/app.js"
_assets/_js/_custom/factories.js"
_assets/_js/_custom/controllers.js"
I have double checked that these files are all present in the locations I have listed in the script src attributes so no problems there.
The Google Map plugin is being loaded/initialised within my controller.js file via the following:
angular.module('sampleAppNameHere.controllers', ["google-maps".ns()])
.config(['GoogleMapApiProvider'.ns(), function (GoogleMapApi) {
GoogleMapApi.configure({
key: 'MY-KEY-HERE',
v: '3.17',
libraries: 'weather,geometry,visualization'
});
}])
Further down in the controller where I want the Google Map to be loaded from I have the following set-up:
.controller('LocationController', ['$scope', '$http', '$stateParams', '$sce', '$ionicLoading', '$ionicPopup', '$timeout', 'Logger'.ns(), 'GoogleMapApi'.ns(), 'RetrieveAppContent', function($scope, $http, $stateParams, $sce, $ionicLoading, $ionicPopup, $timeout, $log, GoogleMapApi, RetrieveAppContent)
{
function parseLocations(locationID, locationName, regionName)
{
// Retrieve factory function to return AJAX loaded data
RetrieveAppContent.retrieveRemoteContentForApp().then(function(locationObj)
{
// Loop through associative array formed from parsed AJAX data into factory method
angular.forEach(locationObj.locations, function(v, k)
{
if(locationID === v.recordID)
{
// Other content in here bonded to scope
$scope.mapLongitude = v.mapLongitude;
$scope.mapLatitude = v.mapLatitude;
$scope.mapZoom = v.mapZoom;
}
});
GoogleMapApi.then(function(maps)
{
// Alerts placed in here are triggered when the template loads
maps.visualRefresh = true;
$scope.map = { center: {latitude: $scope.mapLatitude, longitude: $scope.mapLongitude }, zoom: $scope.mapZoom };
$scope.options = { scrollwheel: false };
});
});
}
}
The parseLocations function is called shortly afterwards in the above controller and the content is all loaded into the template exactly as intended so no problems there BUT the angular map will not render.
The following segment is from the view where the content for the controller is loaded/displayed and where the map is located:
<ion-view title="{{ locationName }}">
<ion-content class="location-panel" ng-controller="LocationController">
<!-- Render Google Map -->
<div id="map-canvas">
<ui-gmap-google-map center="map.center" zoom="map.zoom"></ui-gmap-google-map>
</div>
I have set the following class within the CSS that the app uses:
.map-canvas,
.angular-google-maps-container {
height: 400px;
}
But I see NO rendering of the map only a white space fixed to the above height.
Can anyone offer any suggestions/heads-up on what might or could be causing the non-rendering of the Map and what steps I might be able to take to rectify this?
My thanks in advance for any help that folk might be able to provide.....and my apologies if the code formatting is a bit wonky! :-/
Check your CSS class
.angular-google-maps-container
should be
.angular-google-map-container.
I believe you have it as maps not map.
First of all thanks to Brad for his answer to my question (the heads up on the CSS class name WAS useful for my most recent attempt in using this package!).
I originally solved this, back in November 2014, by writing my own custom directive which provided the Google Map functionality that I needed.
Since then I've had occasion to use the latest version of the AngularJS Google Maps package (angular-google-maps 2.0.12 2015-01-29) and have implemented this without problem (noting Brad's tip on the class name).
Thanks once again.
New to angular and have a page in which I have the app and controller defined. After the controller, I am trying to display a value I get back from a Node Rest call (which I get correctly). If I put {{1+1}} i get a value... I do not get a value for {{test}} or {{stock.symbol}}. I do see them in the scope variable in firebug ....
Not sure what I am doing wrong with the definition of the module. Any help would be appreciated! Code snippets below ...
HTML
=====
<html lang="en" ng-app="tradingSystem">
..
..
{% block content %}
{% include "includes/carousel.html" %}
<div class="container" ng-controller="StockListCtrl">
<h3>Test: {{ test }} </h3>
<h3>Symbol: {{ stock.symbol }}</h3>
{% block content %}
{% include "includes/carousel.html" %}
<div class="container" ng-controller="StockListCtrl">
<h3>Test: {{ test }} </h3>
<h3>Symbol: {{ stock.symbol }}</h3>
App.JS
=======
'use strict';
/* App Module */
var tradingSystem = angular.module('tradingSystem', [
'ngRoute',
'tradingSystemAnimations',
'tradingSystemControllers',
'tradingSystemFilters',
'tradingSystemServices'
]);
controllers.js
=============
'use strict';
/* Controllers */
var app = angular.module('tradingSystem', []);
app.controller('LoginCtrl', ['$scope', 'User', function($scope, User) {
$scope.authenticate = function (user)
{
$scope.user = User.authenticate({emailAddress: user.emailAddress, password: user.password});
alert("Received " + $scope.user);
};
}]);
app.controller('StockListCtrl', ['$scope', '$http', function($scope, $http) {
$scope.test = 'This is a test';
$http.get('/api/stocks')
.success(function (stocks) {
if (!stocks) {
console.log("No results from api/stocks service ");
}
else
{
$scope.stocks = stocks;
console.log("Results: " + stocks);
console.log("Stocks Fetched: " + $scope.stocks.length)
$scope.stock = stocks[0];
console.log("Scope: " + $scope);
alert(stocks[0].symbol);
console.log($scope);
}
})
.error(function (reason) {
alert(reason);
});
}]);
The problem was related to using Swig as my rendering engine with Express. Once I added swig.setDefaults({ varControls: ['<%=', '%>'] }); // or anything besides ['{{', '}}'] to change the defaults, the page rendered the AngularJS variables.
As Alex C mentions you are re-declaring the app module in the controllers file - as the docs note at https://docs.angularjs.org/api/ng/function/angular.module - if you are wanting to retrieve an existing module you need to leave off the second parameter, eg.
angular.module('myModule', []); //creates a new module
angular.module('myModule'); //retrieves an existing module
So given that you have already declared your tradingSystem module and assigned it to a global variable (not the best approach for larger apps, but ok for a small example) in your controller.js you need to drop var app = angular.module('tradingSystem', []); and have
tradingSystem.controller('LoginCtrl', etc.
but you do have tradingSystemControllers as a dependency of your tradingSystem module, so maybe in your controllers file you meant to put:
var tradingSystemControllers = angular.module('tradingSystemControllers', []);
EDIT: 20/7/2014
As far as setting up for larger applications goes, not my tips or best practice, I am just following what other leaders in this area are suggesting and it is working for me for now ;-)
I think that https://github.com/ngbp/ngbp is a good example of an Angular app structure broken down by module, with all files (module js, templates, less, unit tests) related to a module in the same folder. ngbp also has a good automated workflow for compiling both a dev and production build with karma testing, jshint, etc. built in. There are lots of angular seed/boilerptlate projects around now - not saying the ngbp is the best as I haven't looked at them all in detail - but the approach of putting all related module files together in the module folder is a good one I think, and the approach suggested by the Angular team now - https://docs.google.com/a/core-ed.ac.nz/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/pub
In relation to using
var tradingSystem = angular.module(
that I mentioned in my first answer - given that you have easy access to any angular modules via
angular.module('myModule')
assigning a module to a global variable doesn't have any huge advantage, and potentially clutters the global name space in a large app. I like the approach put forward by a couple of others which is to use an IIFE to encapsulate each module a bit better - details here - http://caughtexceptions.blogspot.co.nz/2014/07/angular-module-setup.html
To this end I have modified the ngbp build process slightly to use grunt-wrap to wrap each module definition in its own IIFE as part of build process.
Upon updating from angular 1.2.0-RC.2 to 1.2.0-RC.3 I noticed a breaking change triggered by changes to how ngBindHtmlDirective parses scope data (via this change). What I do is fetch a piece of SVG and then display it (SVG is valid and all that).
I have this bit of template markup:
<div ng-controller="MainCtrl">
<div ng-bind-html="svg"></div>
</div>
And some logic on my app that requests the SVG from the server and then assigns it to $scope:
app.controller('MainCtrl', ['$scope', '$sce', 'API', function($scope, $sce, API) {
API.getSVG().then( function(resp) {
$scope.svg = $sce.trustAsHtml(resp.data.svg);
});
}]);
This used to work on RC2 but doesn't anymore on RC3. Any idea what I'm doing wrong? thanks.
I set up a simple jsFiddle and it works fine with Angular 1.2.0-RC3 up to 1.2.4.
JS
$scope.svg = $sce.trustAsHtml('<svg xmlns="http://www.w3.org/2000/svg"><circle r="50"/></svg>');