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) {
...
Related
I'm a complete Angular noob and trying to do some fancy stuff quickly, so forgive me if this is a dumb question.
I've created a website that uses routing, and I'm using ui-router for the routing instead of the standard Angular router. The theory is still the same - I have an index.html page in the root of my website which is the "master" or "host" page, and loginView.htm, which is a partial, exists in a separate directory.
The mainController for the project is loaded in the index.html page. Referencing this controller does NOT cause an error or problem.
What I'd like to do, in order to keep code manageable and small, is have the custom controller for a partial page lazy load when I load the partial, and then associate that partial page with the newly loaded controller. Makes sense, right? I don't want to load all the controllers by default, because that's a waste of time and space.
So my structure looks like this (if it matters to anyone):
Root
--app/
----admin/
------login/
--------loginView.html
--------loginController.js
--mainController.js
index.html
This is my loginController code. For testing purposes, I have made the mainController code match this exactly.
var loginController = function ($scope, $translate) {
$scope.changeLanguage = function (key) {$translate.use(key); };
};
angular.module('app').controller('loginController', loginController);
Finally, here is my routing code:
function config($stateProvider, $urlRouterProvider, $ocLazyLoadProvider) {
$urlRouterProvider.otherwise("/admin/login");
$stateProvider
.state('login', {
url: "/admin/login",
templateUrl: "app/admin/login/loginView.html",
controller: loginController,
resolve: {
loadPlugin: function ($ocLazyLoad) {
return $ocLazyLoad.load([
{
name: 'loginController',
files: ['app/admin/login/loginController.js']
}
]);
}
}
})
;
}
angular
.module('app')
.config(config)
.run(function ($rootScope, $state) {
$rootScope.$state = $state;
});
Now - if I remove the whole "resolve" section, and change the controller to "mainController", everything works. The page loads, the buttons work, they call the "changeLanguage" function and everything is wonderful.
But I want the "changeLanguage" feature to reside in the loginController because that's the only page that uses it. So when the code looks like it does above, an error fires("Uncaught Error: [$injector:modulerr]") and the partial page fails to load.
I don't understand what I'm doing wrong, and I'm not finding what I need via Google (maybe I just don't know the right question to ask).
Help?
Looking through the docs I cannot find the name property for ocLazyLoad#load.
Try the following:
resolve: {
loadPlugin: function ($ocLazyLoad) {
return $ocLazyLoad.load(['app/admin/login/loginController.js']);
}
}
Or, pre configure it in a config block:
app.config(function ($ocLazyLoadProvider) {
$ocLazyLoadProvider.config({
modules: [{
name: 'loginController',
files: ['app/admin/login/loginController.js']
}]
});
});
// then load it as:
$ocLazyLoad.load('loginController');
I want to show a laravel blade view file in angular JS directive by
var commentsApp = angular.module('CommentApp',[]);
commentsApp.directive('commentForm',function(){
return {
restrict: 'EA',
replace: 'true'
templateURL: 'views/comments/comment-form.blade.php'
}
});
I want to use it by angular directive instead of
#include('comments.comment-form')
Where is my problem? How to solve this.
Thank you.
First you must define a route in laravel
Route::get('comment-form', function() {
return view('comments.comment-form');
});
Then you can use it in AngularJS
var commentsApp = angular.module('CommentApp', []);
commentsApp.directive('commentForm', function() {
return {
restrict: 'EA',
replace: 'true',
templateURL: 'comment-form'
}
});
Answer above is a good idea, however i dont like the idea of asking for a template by routing, We would create a route for each component :c . I leave my solution here:
In gulpfile.js inside elixir function add this line:
var elixir = require('laravel-elixir');
elixir(function(mix) {
mix.copy('resources/assets/js/angular/components/**/*.template.html', public/angular-templates');
//Find all files with suffix .template.html
});
As you notice it, i created a folder called 'angular' and then another one called 'components', there we will have our components
Angular-----------------------------
--Components------------------------
----my-component.directive.js-------
----my-component.template.html------
We have to create a global angular variable taking our browser window origin (www.myapp.com, localhost:8000, etc) by doing:
angular.module('myModule',[])
.value('pathAssets', location.origin + '/angular-templates/')
In our templateUrl we will call the template by writting:
templateUrl: pathAssets + '../angular-templates/my-template.html',
I have to say we have to concat our angular files in a file, otherwise it won't work D: if you don't know how to do it, add these lines in your gulpfile.js
mix.scripts([
'../../../bower_components/angular/angular.min.js',
'angular/app.js',
'angular/controllers/**/*.controller.js',
'angular/components/**/*.directive.js',
'angular/bootstrap.js',
], 'public/js/app.js'); //We concatenate angular files saving them in app.js
Finally execute the command 'gulp' in terminal(In our project), it should generate a new folder in public called angular-templates.
That's it :)
(function(angular) {
'use strict';
angular.module('app').component('bringTeamToEvent', {
templateUrl: '/assets/ng/app/team/bringTeamToEvent.html',
bindings: {
hero: '='
}
});
})(window.angular);
Just work from the public directory, no need to compile assets and move if you dont need to.
Then add the # symbol to tell blade to ignore and let angular do its work within the template
<span>Name: #{{ $ctrl.hero.name}}</span>
I am running through a course at the moment on AngularJS and it has just introduced the concept of routing.
My problem is the app.config function is setup in app.js however, the function doesn't seem to ever be called and therefore the routes are not setup.
The common problem is the ngRoute not being declared however, it is. I'm not sure if there is a problem with the versions of Angular that I'm using but these were taken from the online course.
I have a public plnkr for anyone to view and have a look at http://plnkr.co/edit/L2FG4M?p=preview
(function() {
var app = angular.module("githubViewer", ["ngRoute"]);
app.config(function($routeProvider) {
// If we navigate to /main then the page used will be main.html and the controller
// MainController, if however something else is provided then we will
// redirect to /main as well
$routeProvider.when("/main", {
templateUrl: "main.html",
controller: "MainController"
})
.otherwise({
redirectTo: "/main"
});
});
}());
Any help is appreciated, I've exhausted my options now.
Thanks
Marc
In your MainController.js file, you defined a new module with same name as in app.js:
angular.module("githubViewer", []);
What you want to do is retrieve the already defined module. You can acheive that by removing the []:
angular.module("githubViewer");
Look here at the "Creation versus Retrieval" section.
I just took an app I'm working on and converted it to a Plunk but Angular and/or ui-router is not populating the two views I have in index.html. On my local box the app loads fine but there I have the app modularize. So when I converted it to a Plunk I had to rewire the files together since I can't make modules in Plunker AFAIK. Also, when I load the Plunk in a separate window and open Dev Tools I get no errors so I'm at a loss right now.
Here is link to the Plunk code I made:
http://plnkr.co/edit/2f1RITT6ysZhB5i0UcUw?p=preview
And here is the link to the embedded view (more convenient if you want to use Dev Tools):
http://embed.plnkr.co/2f1RITT6ysZhB5i0UcUw/preview/posts
I should mention that the route has to end in /posts since that it the url of the state named posts. I have no state defined for the root / url. Also the following url failed:
http://embed.plnkr.co/2f1RITT6ysZhB5i0UcUw/posts
Thanks in advance.
I've made few changes. Here is a working plunker
Firstly I upgraded your version to UI-Router 0.2.13 (fixes some issues, simply always use the latest)
The /post is now default
//$urlRouterProvider.otherwise('/');
$urlRouterProvider.otherwise('/posts');
I changed your controller, to not use router params,
// wrong old
/*
app.controller('ProfileCtrl', function ($scope, $routeParams, Profile) {
var uid = $routeParams.userId;
$scope.profile = Profile.get(uid);
Profile.getPosts(uid).then(function(posts) {
$scope.posts = posts;
});
});
*/
// the way with UI-Router
app.controller('ProfileCtrl', function ($scope, $stateParams, Profile) {
var uid = $stateParams.userId;
$scope.profile = Profile.get(uid);
...
JUST to know what is post holding
Also, the passed userId into state contains values like: "simplelogin:82", to observe taht, I added overview of processed post, which is showing info like this:
{
"creator": "3lf",
"creatorUID": "simplelogin:82", // this is passed as userId, is it ok?
"title": "a",
"url": "http://a",
"$id": "-JazOHpnlqdNzxxJG-4r",
"$priority": null
}
Also, this is a fixed way how to call state posts.postview
<!-- wrong -->
<!-- <a ui-sref="posts({postId:post.$id})">comments</a> -->
<!-- correct -->
<a ui-sref="posts.postview({postId:post.$id})">comments</a>
And alos, if the postview should be injected into main area, this should be its defintion
var postView = {
name: 'posts.postview',
parent: posts,
url: '/:postId',
views: {
'navbar#': {
templateUrl: 'nav.tpl.html',
controller: 'NavCtrl'
},
//'#posts.postview': {
'#': {
templateUrl: 'postview.tpl.html',
controller: 'PostViewCtrl'
}
}
};
Check it all here
SUMMARY: Working navigation is among posts - users... the "comments" link is also working, but the target is just loaded ... with many other errors... out of scope here
I work on a Ionic project (AngularJS + Apache Cordova aka Phonegap).
The first code's lines of my project are 4 months, and yesterday, the application nolonger works on emulators and real devices, but still work into chrome window. So I suppose my angular code is correct, but I don't know where is the issue, and I didn't know how to handle it.
At the beginning I coded directly in my www folder, and I test it either into chrome with devtools and device emulation, or in chrome with the Apache Ripple extension, and at times I install it into my real device (Nexus S).
I recently installed grunt and bower into my project for common tasks, and I decided to reorganize my project folder.
Then now, I code into a src folder, and :
before testing in chrome, I run grunt 'dev' tasks witch creates a www folder and includes a dedicated index.html linked to scr/ js, html,css and other res files.
before testing in emulator or real device, I run grunt 'prod' tasks witch creates a www folder and includes build or copy all the needed files to the the app (app.min.css, app.min.js, templates, fonts and media files, icon).
Both of it work fine in chrome, but when I build (via either cordova-cli or phonegap build) and install the app on emulator or real device, I get the splash screen and then, a permanent white screen.
I tried to debug it with the help of weinre I and note that the js console doesn't catch any thrown error.
But I placed some console.log and it appears that the routing is broken.
angular.module('app').run() is executed, but the first controller that is AppCtrl is never executed.
Here is my module code (important parts for this post) :
(function(){
angular.module('app', [
'ionic',
'ngCordova',
'app.auth',
'app.model',
'app.action',
// 'app.test',
])
.run(['$ionicPlatform',
function($ionicPlatform) {
alert("app.run() runs ...");
}])
.config(['$stateProvider','$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
var tmplt_dir = 'modules/app/tmplt';
var tmplt = function(viewName){
return tmplt_dir + '/' + viewName + '.html' ;
};
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: tmplt('app') ,
controller: 'AppCtrl'
})
.state('app.main', {
url: "/main",
abstract: false,
views: {
"menuContent" : {
templateUrl: tmplt('main') ,
controller: 'MainCtrl'
}
}
})
.state('app.main.home', {
url: "/home",
views: {
'homeTabContent' :{
templateUrl: tmplt('home') ,
controller: 'HomeCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/main/home');
}])
.controller('AppCtrl', [ '$rootScope', '$cordovaToast', '$window',
function($rootScope, $cordovaToast, $window) {
alert('AppCtrl runs...');
$rootScope.notImplementedException = function(){
var message = "Bientôt disponible.";
try {
$cordovaToast.showShortCenter(message);
} catch(e){
alert(message);
}
};
$rootScope.browserOpen = function(href){
var ref = $window.open(href, '_system', 'location=yes');
};
}])
.controller('MainCtrl', [ function() {
alert('MainCtrl runs...');
}])
.controller('HomeCtrl', [ '$rootScope','$auth', '$app',
function($rootScope, $auth, $app) {
alert('HomeCtrl runs...');
if (!$auth.checkLogin()) {
$auth.authError();
}
$rootScope.appName = $app.name;
}])
})();
The only alerts that appears is :
app.run() runs ...
So, the alerts that don't appear are :
AppCtrl runs...
MainCtrl runs...
HomeCtrl runs...
Remember that in chrome, all works perfectly !
This issue is really baffling and I've already lost a few hours to track it, unsuccessfully.
Any idea ?
I solved my problem.
In fact, I wrote an httpRequestInterceptor factory which check if an url have to be signed to use my Rest API.
A recent change of the structure of my project folder causing this factory returning sometimes a wrong result, then signing some local url and causing bad routing, then whitescreen.
Run ionic build ios
Run ionic emulate ios
Open Safari-> Develop -> Simulator -> index.html (for your app)
Check console for errors (if any)
Press reload (usually on top left) and monitor the console tab for errors.
If you are using Parse (or such), make sure you initialize these before using them in your code. This is a common reason for white screens.
This state does not exists
$urlRouterProvider.otherwise('/app/main/home');
I think it should be
$urlRouterProvider.otherwise('/home');
We use gapdebug to debug our ionic applications. You can also debug realtime on your device if its plugged in to the computer and its a very good debugger for any emulator.
For me i solved it by replacing this
$stateProvider.state('nameOfState', {
templateUrl: '/templates/nameOfTemplate.html',
})
With this
$stateProvider.state('nameOfState', {
templateUrl: './templates/nameOfTemplate.html',
})
Try to add a "." before the full URL in "templateUrl". Worked for me!