I've got a strange bug that only appears when running my web appliction in karaf but not on the webpack-dev-server. When running the web app from Karaf when I open the dialog, I get this error in the browser console
angular.js:14516 Error: [$injector:unpr] Unknown provider: nProvider <- n
http://errors.angularjs.org/1.6.3/$injector/unpr?p0=nProvider%20%3C-%20n
The component is responsible for displaying a table. The columns should be editable so i've implemented a stock dialog from the angular material demos. See -> https://material.angularjs.org/latest/demo/dialog and a multi select with the option to search -> https://material.angularjs.org/latest/demo/select
Here follows the code:
ctrl.editColumns = (event) => {
$mdDialog.show({
template: require('./edit-column-dialog.template.html'),
clickOutsideToClose: true,
scope: $scope,
preserveScope: true,
controller: EditColumnsDialogController
})
}
function EditColumnsDialogController ($element) {
ctrl.searchTerm = ''
ctrl.copySelectedColumns = ctrl.selectedColumns
// The md-select directive eats keydown events for some quick select
// logic. Since we have a search input here, we don't need that logic.
$element.find('input').on('keydown', (ev) => {
ev.stopPropagation()
})
}
I use $element for the reason detailed in the comment above. What I can't get my head around is that this works fine on the web pack dev server. The only difference between the settings for web pack are:
// Add build specific plugins
if (isProd) {
config.plugins.push(
// Only emit files when there are no errors
new webpack.NoEmitOnErrorsPlugin(),
// Minify all javascript, switch loaders to minimizing mode
new webpack.optimize.UglifyJsPlugin({
sourceMap: true
}),
// Copy assets from the public folder
// Reference: https://github.com/kevlened/copy-webpack-plugin
new CopyWebpackPlugin([{
from: path.join(__dirname, '/app/public')
}])
)}
Any answers are much appreciated.. or suggestions for isolating the problem!
Minifiers break code that uses Implicit Annotation. Instead, use $inject Property Annotation:
//USE $inject property annotation
EditColumnsDialogController.$inject = ["$element"];
function EditColumnsDialogController ($element) {
ctrl.searchTerm = ''
ctrl.copySelectedColumns = ctrl.selectedColumns
// The md-select directive eats keydown events for some quick select
// logic. Since we have a search input here, we don't need that logic.
$element.find('input').on('keydown', (ev) => {
ev.stopPropagation()
})
}
From the Docs:
Implicit Annotation
Careful: If you plan to minify your code, your service names will get renamed and break your app.
— AngularJS Developer Guide - Implicit Dependency Annotation
Related
I'm building a Chrome extension and surprisingly, I could create one AngularJS app for the extension side and another for the content script side. The latter is useful to work with a modal-like element injected in the page. I injected this app with this content script:
var myApp = angular.module('ContentApp', []);
/**
* Append the app to the page.
*/
$.get(chrome.runtime.getURL('templates/modal.html'), function(data) {
$($.parseHTML(data)).appendTo('body');
// Manually bootstrapping AngularJS app because template was also manually imported.
angular.element(document).ready(function() {
angular.bootstrap(document, ['ContentApp']);
});
});
The problem comes now that modal.html is getting big and I still have to add more elements. I thought that I could start creating components in Angular and did it like this:
angular.module('ContentApp').
component('greetUser', {
template: 'Hello, {{$ctrl.user}}!',
controller: function GreetUserController() {
this.user = 'world';
}
});
This actually works. I can see the Hello, world message in the rendered page. But when I changed template for templateUrl, it failed:
// This doesn't work
templateUrl: 'templates/component.html',
// Neither does this
templateUrl: 'templates/component.html',
// Although this is similar to the way I got the main template, it didn't worked either
templateUrl: chrome.runtime.getURL('templates/component.html'),
Worth to mention that I added the permission to manifest.json:
"web_accessible_resources": [
"templates/*"
],
The error that I got in the console is this:
Error: [$sce:insecurl] http://errors.angularjs.org/1.5.11/$sce/insecurl?p0=chrome-extension%3A%2F%2Fext_id%2Ftemplates%2Fmodal.html
at chrome-extension://ext_id/scripts/lib/angular.min.js:6:426
at getTrusted (chrome-extension://ext_id/scripts/lib/angular.min.js:154:156)
Does anyone know how to make it work? Or am I asking too much for a Chrome extension?
I found the answer in this link. Thanks to faboolous who pointed me in the right direction ;)
Since templateURL is processed before $scope execution, the proper way to secure a template path in a Chrome extension is this:
// This works. Yay!
angular.module('ContentApp').
component('greetUser', {
templateUrl: ['$sce', function ($sce) {
return $sce.trustAsResourceUrl(chrome.runtime.getURL('templates/component.html'));
}],
controller: function ($scope) {
...
I have an AngularJS 1.6 app that loads a list of app modules fetched from the server. Every app has a different list of modules, so it would mean a lot of overhead code to create one unique route per module.
We are using ui-router, and it provides a really cool route config method called componentProvider which allows us to dynamically load a component pages on (in our case) the $routeParams.
Here is the working Angular 1.6 code:
//...
.state('applications.apps.modules', {
url: '/:moduleSlug',
data: {
addToSideMenu: false,
},
// create a dynamic component
componentProvider: ($stateParams: StateParams) => {
// This outputs "application-<name of module>"
return `application${capitalizeFirstLetter(snakeToCamel($stateParams.moduleSlug))}`;
},
resolve: {
application: (applications, $stateParams: StateParams) => {
return applications.filter(app => app.slug === $stateParams.appSlug)[0];
},
},
})
//...
This code will return a string application-<name of module>, and it allows us to load that module dynamically.
We're trying to find a way to do the same thing in that app but in Angular 4.
Any idea?
I'm constantly failing to inject the $log service in a minify save way into a controller class of a component.
To check the injection is save, I added ng-strict-di to my app. This in terms causes an SearchResultController is not using explicit annotation and cannot be invoked in strict mode which is fine, since I'm relying on implicit injection right now.
So I added an explicit injection to my component implementation:
import htmlTemplate from './searchInput.html';
class SearchInputController {
constructor($log) {
this._log = $log;
this.searchText = 'Text to search for';
}
handleUpdate() {
this.onChange({value: this.searchText});
}
doubleMe(i) {
this._log.debug('SearchInputController.doubleMe: i='+i);
return i+i;
}
}
SearchInputController.$inject = ['$log'];
let searchInputComponent = {
template: htmlTemplate,
controller: SearchInputController,
bindings: {
onChange: '&'
}
};
export default searchInputComponent;
This has no effect the error message is still complaining about the missing injection.
I also tried ng-annotate-loader and ng-annotate-webpack-plugin. And also tried the /*#ngInject*/ and 'ngInject'; type annotations. All of this has no effect.
Any ideas how to get the dependency injection working?
Your annotation appears to be correct for SearchInputController, but the error message is complaining about a different controller SearchResultController. I suggest you need to annotate that one also.
Use https://babeljs.io/repl/ to check how ES6 compiles down to ES5. This can be useful when trying to trace errors in annotation. Using ng-annotate in some form should also work when you annotate the correct controller.
I'm extending an existing Angular-MVC.NET application.
There are two features: transformations (exisitng) and embossing (the one I'm creating). Both of them use provider classes that call an underlying logic.
I copied all the logic for the transformation (Angular and MVC model and views), renamed evrthing accordingly, and created the new route for this feature in app.router.js
$routeProvider.when('/embossing', {
templateUrl: 'app/views/embossing.html',
params: { test: "hola" },
resolve: {
deps: [
"$ocLazyLoad", function (a) {
debugger;
return a.load([jqload.c3, jqload.sparkline])
.then(function () {
return a.load({
name: "app.directives",
files: ["app/scripts/lazyload/directives/sparkline.directive.js"]
});
})
.then(function () {
return a.load("angular-c3");
})
.then(function () {
return a.load("easypiechart");
});
}
]
}
});
Now I'm able to navigate without issues from the angular transformation controller to the embossing view by using
$location.path('/embossing');
The thing that happens is that when I load directly the view by entering http://localhost:1623/embossing/ or if I hit enter on the browrser's URL bar after navegating from transformation (as I mentioned before) I get this error
How come I'm able to navigate to the view but when I load it directly I get that error?
Is there something that I'm missing? What could be wrong?
Thanks
MVC and AngularJS Routing - 403.14 - Forbidden
It got solved by renaming the "Embossing" folder (the one that contains EmbossingProvider.cs)
It seems that there cannot be a folder name as a route. eg:
$routeProvider.when('/embossing', was conflicting with "Embossing" folder
I have built a multi step form following this tutorial: http://scotch.io/tutorials/javascript/angularjs-multi-step-form-using-ui-router Everything is working well.
I now want to use Twitter's typeahead.js on those forms. So I need to make the typeahead call on the input being loaded with angular-ui-router.
I noticed angular-ui-router provides a onEnter callback that gets called when the state becomes active. Making the call to the typeahead function from in there doesn't seem to work, it seems the call is made before the view is loaded (not 100% sure of that).
How can I initialize typeahead on my input field loaded with angular-ui-router?
What I tried:
.state('questionnaire.relationship', {
url: '/relationship',
templateUrl: 'questionnaire/relationship.html',
onEnter: function(){
var relationshipList = ['brother', 'sister', 'father', 'mother'];
var relationships = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: $.map(relationshipList, function(relationship) { return { name: relationship }; })
});
relationships.initialize();
$('#bloodhound .typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'relationships',
displayKey: 'name',## Heading ##
source: relationships.ttAdapter()
});
alert('finished');
}
})
When entering the questionnaire.relationship state, I see the alert popup before the view. Then the view with my input loads properly, but typeahead isn't working. There are no js error in the console.
I also made sure the typeahead call is working when used outside of angular-ui-router.
Have you tried using angular ui bootstrap's typeahead? It was built for angular without the dependency on JQuery
http://angular-ui.github.io/bootstrap/