Multiple Angularjs Applications (Driving Portlets) - javascript

I have a use case that requires the loading of separate angular applications.
Based on several stack overflow questions and this google thread, it's doable. However, I can't get it to work.
Looking at the documentation:
http://docs.angularjs.org/api/angular.bootstrap
It looks like you need to provide the element (what is the right way to get a handle on the element?), and then how to tie it back to config, controllers, etc. And how would this work with routes? IE how does collision work, ie app a and app b map /foo to /fooa.html and /foob.html respectively... or each app describes its own .otherwise?
Thanks!

So given the requirement that this be a service driven content the only way I can see to do this is kind of a mix between angular and standard html practices. Effectively you'll want to take a page from the plunker book and use Iframes to contain each individual portlet.
<!doctype html> <html lang="en">
<body ng-app="plunker" ng-controller="MainCtrl">
<!-- define foo -->
<div>
<ul class="menu">
<li>foo1</li>
<li>foo2</li>
</ul>
<iframe seamless="true" ng-src="foo.index.html{{fooRoute}}"></iframe> </div>
<div>
<ul class="menu">
<li>bar1</li>
<li>bar2</li>
</ul>
<iframe seamless="true" ng-src="bar.index.html{{barRoute}}"></iframe> </div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script> <script src="app.js"></script> </body> </html>
Then on each of these portlets you'll want to have a completely separate application (including the loading of resources).
<!doctype html>
<html lang="en">
<body ng-app="fooApp">
<div ng-view></div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script>
var app = angular.module('fooApp', ['fooApp.controllers']);
// Configure the app
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/foo1', {template: '<h1>Foo</h1><h2>foo1</h2>', controller: 'MyCtrl1'});
$routeProvider.when('/foo2', {template: '<h1>Foo</h1><h2>foo2</h2>', controller: 'MyCtrl2'});
}]);
angular.module('fooApp.controllers', []).
controller('MyCtrl1', [function () {
console.log("fooApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("fooApp.MyCtrl2 invoked.");
}]);
</script>
</body>
</html>
This is a little less efficient for loading than utilizing a common application base but at the moment this isn't feasible. There is talk at the angular-ui's ui-router team about controlling independent views which may be a workable solution for you but it is currently not implemented, you can follow the discussion at https://github.com/angular-ui/ui-router/issues/84 and chime in with your need. There is also now an issue specifically for this on the ui-router issues list at https://github.com/angular-ui/ui-router/issues/160.
Working plunker of this design: http://plnkr.co/edit/sPoK3I?p=preview

Ok so I figured out how to do this using the angular ui-router the key comes down to the ability of the angular ui-router to transition states without effecting the URL.
The steps to get this working
First instantiate each application as a stand alone application using
a manual bootstrap to an ID'd element.
Attach the ui-router $stateProvider to each application to drive the internal state transitions (routes).
You must leave off the url key here for each defined state or you'll reset the page by changing the url on each state transition.
Setup a state function in a main controller to drive state changes.
The following is the code to get this working:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.0.x" src="http://code.angularjs.org/1.0.7/angular.min.js" data-semver="1.0.7"></script>
<script src="angular-ui-states.min.js"></script>
<script src="app.js"></script>
</head>
<!-- define foo -->
<div id="fooApp" ng-controller="MainCtrl">
<ul class="menu">
<li>foo1</li>
<li>foo2</li>
</ul>
<div ui-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('fooApp', ['fooApp.controllers', 'ui.state']);
// Configure the app
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('foo1',
{
template: '<h1>Foo</h1><h2>foo1</h2>',
controller: 'MyCtrl1'
})
.state('foo2',
{
template: '<h1>Foo</h1><h2>foo2</h2>',
controller: 'MyCtrl2'
});
}]);
angular.module('fooApp.controllers', [])
.controller('MainCtrl', ['$scope', '$state', function($scope, $state){
$scope.state = function(name){
console.log('Transition to state ' + name);
$state.transitionTo(name);
}
}])
.controller('MyCtrl1', [function () {
console.log("fooApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("fooApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('fooApp');
console.log(div);
angular.bootstrap(div, ['fooApp']);
</script>
<!-- define bar -->
<div id="barApp" ng-controller="MainCtrl">
<ul class="menu">
<li>bar1</li>
<li>bar2</li>
</ul>
<div ui-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('barApp', ['barApp.controllers', 'ui.state']);
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('bar1',
{
template: '<h1>Bar</h1><h2>bar1</h2>',
controller: 'MyCtrl1'
})
.state('bar2',
{
template: '<h1>Bar</h1><h2>bar2</h2>',
controller: 'MyCtrl2'
});
}]);
angular.module('barApp.controllers', [])
.controller('MainCtrl', ['$scope', '$state', function($scope, $state){
$scope.state = function(name){
console.log('Transition to state ' + name);
$state.transitionTo(name);
}
}])
.controller('MyCtrl1', [function () {
console.log("barApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("barApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('barApp');
console.log(div);
angular.bootstrap(div, ['barApp']);
</script>
</body>
</html>
Working plunker of this solution at http://plnkr.co/edit/bXSN8qSMdioZJLYs2zyk?p=preview
Please see my previous answer for a discussion currently occurring to make portlet support more intrinsic in the ui-router.

Figured it out. Here's how to successfully load two angular applications in parallel. Also see that I named the controllers the same for each app to show that dependencies will not collide (since they are scoped within each respective app via module):
<!doctype html>
<html lang="en">
<body>
<script src="lib/angular/angular.js"></script>
<!-- define foo -->
<div id="fooApp">
<ul class="menu">
<li>foo1</li>
<li>foo2</li>
</ul>
<div ng-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('fooApp', ['fooApp.controllers']);
// Configure the app
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/foo1', {template: '<h1>Foo</h1><h2>foo1</h2>', controller: 'MyCtrl1'});
$routeProvider.when('/foo2', {template: '<h1>Foo</h1><h2>foo2</h2>', controller: 'MyCtrl2'});
}]);
angular.module('fooApp.controllers', []).
controller('MyCtrl1', [function () {
console.log("fooApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("fooApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('fooApp');
console.log(div);
angular.bootstrap(div, ['fooApp']);
</script>
<!-- define bar -->
<div id="barApp">
<ul class="menu">
<li>bar1</li>
<li>bar2</li>
</ul>
<div ng-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('barApp', ['barApp.controllers']);
// Configure the app
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/bar1', {template: '<h1>Bar</h1><h2>bar1</h2>', controller: 'MyCtrl1'});
$routeProvider.when('/bar2', {template: '<h1>Bar</h1><h2>bar2</h2>', controller: 'MyCtrl2'});
}]);
angular.module('barApp.controllers', []).
controller('MyCtrl1', [function () {
console.log("barApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("barApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('barApp');
console.log(div);
angular.bootstrap(div, ['barApp']);
</script>
</body>
</html>
The only remaining question is how to deal with routing collisions.

Well you have 2 choices here:
if you create them as angular.module() there would not be a way atm to connect the modules with each other.
if you create directives with a templateURL to lazyload your components you could broadcast shared attributes and listen to them and you could use the same services in your app.
Probably that would be the best for you.

Related

How to get data from rest api which has basic authentication?

I'm trying to get data from this website through HTTP get method. This website has basic authentication. The data is in JSON format.
This is the rest api website:
(https://shoploapi.herokuapp.com/sellers)
// Code goes here
angular.module('myapp', ['myapp.controller']);
angular.module('myapp.controller', ['myapp.service'])
.controller('testController', function($scope, testService) {
$scope.posts = {};
function GetAllPosts() {
var getPostsData = testService.getPosts();
getPostsData.then(function(post) {
$scope.posts = post.data;
}, function() {
alert('Error in getting post records');
});
}
GetAllPosts();
});
angular.module('myapp.service', [])
.service('testService', function($http) {
//get All NewsLetter
this.getPosts = function() {
return $http.get('https://shoploapi.herokuapp.com/sellers');
};
});
angular.module('myApp', ['base64'])
.config(function($httpProvider, $base64) {
var auth = $base64.encode("bhupendra7:ice123age456");
$httpProvider.defaults.headers.common['Authorization'] = 'Basic ' + auth;
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.5.0" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-base64/2.0.5/angular-base64.js"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body ng-app="myapp">
<h1>Hello Plunker!</h1>
<div ng-controller="testController">
<div>
<ul>
<li ng-repeat="post in posts">
{{post.careof}} {{post.district}} {{post.gender}} {{post.name}}
</li>
</ul>
</div>
</div>
</body>
</html>
Here's the link to my Plunker:
(https://plnkr.co/edit/7pqljm?p=preview)
Can anyone help?
There are 2 problems in your code.
1. You have a typo
In angular.module('myApp', ['base64']), change to module name to myapp
2. The way you have injected your myapp.controller to myapp module
Change it to angular.module('myapp', []); You will also need to reorder your code. Check out the Plunker I have created for you.
Even if you fix the above two problems, you will still face a CORS problem from Heroku. Depending on your server-side technology (NodeJS, Rails etc.), you will need to enable it from the server to be able to communicate with your app. You can also look in to JSONP with AngularJS
Hope this helps

Javascript inside a Angular router

I have build a very basic Angular Router. But now that I want to interact with my elements inside that templateUrl, no javascript gets executed or those elements inside the templateUrl can not be accessed. I have copied the most of the code from this instruction, here.
My index file:
<html ng-app="myApp">
<head></head>
<body ng-controller="mainController">
<a id="btnHome" href="#/">Startseite</a>
<a id="btnPlanner" href="#/planner">LTC-Planner</a>
<a id="btnSocial" href="#/social">LTC-Social</a>
<div id="main">
<!-- angular content -->
<div ng-view></div>
</div>
<script src="js/routing.js"></script>
</body>
</html>
This is my routing.js file:
// Create the angular module
var myApp = angular.module('myApp', ['ngRoute']);
// Configure our routes
myApp.config(function($routeProvider) {
$routeProvider
// Route for the home page
.when('/', {
templateUrl: 'pages/home.html',
controller: 'mainController'
});
});
// Create the controller and inject angular's $scope
myApp.controller('mainController', function($scope) {
$scope.message = 'This is the HOME page';
});
and this is the template file located at pages/home.html:
<button id="btnTest">Say Hello</button>
<script>
var btnTest = document.getElementById('btnTest');
btnTest.addEventListener('click', function(){
console.log('Hello');
});
</script>
maybe one of you got an idea or has seen an alternative.
Thanks,
André
you should try to wrap your html template in a single tag
<div>
<button ng-click="test()">Say Hello</button>
</div>
And remove the script to put the logic inside your controller. Since your using angular, just use ng-click to bind click listener.
myApp.controller('mainController', function($scope) {
$scope.message = 'This is the HOME page';
$scope.test = function() {
console.log('Hello');
}
});

adding module not working

I am still in study mode of angularjs and just 2 day old. I was trying to make module and so i created seperate js file for it and created module like below.
Also added controller.
var app = angular.module("githubViewer", []);
app.controller("MainCtrl", MainCtrl);
But when i run i get error 'MainCtrl' is not a function, got undefined
here is Plunker
Can someone help me?
After looking in plunker,I think you want to create a separate module in separate file for your controllers and add it to your main module.
For that create module for controllers in separate file,
angular.module("githubViewer", [])
.controller('MainCtrl', function($scope,$http) {
//your logic
});
then add it to your main as dependency in main module
angular.module('plunker', ['githubViewer']);
here is working demo : http://plnkr.co/edit/T9p7Uo2DxUVjqS1wuuiA?p=preview
Ok, you're new to angular, so here's a couple of rules which you must follow until you can prove you need to do otherwise.
You can place definition of module in a separate file. In short plunkers it is often an overkill, but that's what you should be doing in realworld-sized apps. Note that I'm talking about only the module here. Not talking about controllers, factories and other stuff.
Separating body of controller from its inclusion into angular does not bring any benefit. Don't do that.
That said, your files should look like this:
# my_app.module.js
angular.module('myApp', []);
# main.controller.js
var app = angular.module('myApp')
app.controller('MainCtrl', MainCtrl);
function MainCtrl() {
// logic here
}
I check your Plunker.
here is Working Plunker as you want logic of controller in seperate js file and module in seperate file
app.js
function MainCtrl($scope,$http) {
var person = {
firstName: "Kiran",
lastName: "Nandedkar"
};
$scope.name = 'World';
var onUserComplete = function(response){
$scope.user = response.data;
}
var onError = function(reason){
$scope.error = "dfdfdf" ;
}
$http.get("https://api.github.com/users/odetocode")
.then(onUserComplete,onError);
$scope.person = person;
};
module.js
var app = angular.module("githubViewer", []);
app.controller("MainCtrl", MainCtrl);
index.html
<!DOCTYPE html>
<html ng-app="githubViewer">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.3/angular.js" data-semver="1.4.3"></script>
<script src="app.js"></script>
<script src="module.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{person.firstName}}!</p>
<div>Login : {{user.login}}</div>
</body>

Angularjs filter search from outside the ng-view [duplicate]

I have a setup with an ng-view (an admin panel) that lets me display orders. I have a search box outside of ng-view that I would like to use to modify my json request. I've seen some posts on accessing things such as the title but was not able to get them to work - perhaps outdated.
Main app stuff:
angular.module('myApp', ['myApp.controllers', 'myApp.filters', 'myApp.services', 'myApp.directives', 'ui.bootstrap']).
config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider.
when('/', {
templateUrl: '/partials/order/manage.html',
controller: 'ManageOrderCtrl'
}).
when('/order/:id', {
templateUrl: '/partials/order/view.html',
controller: 'ViewOrderCtrl'
}).
otherwise({
redirectTo: '/'
});
$locationProvider.html5Mode(true);
}]);
Manage controller:
angular.module('myApp.controllers', [])
.controller('ManageOrderCtrl', ['$scope', '$http', '$dialog', 'config', 'Page', function($scope, $http, $dialog, config, Page) {
// would like to have search value from input #search available here
var getData = function() {
$http.get('/orders').
success(function(data, status, headers, config) {
$scope.orders = data.orders;
});
};
getData();
})
View:
<body ng-app="myApp" >
<input type="text" id="search">
<div class="ng-cloak" >
<div ng-view></div>
</div>
</body>
If you're going to access stuff outside the <div ng-view></div>, I think a better approach would be to create a controller for the outer region as well. Then you create a service to share data between the controllers:
<body ng-app="myApp" >
<div ng-controller="MainCtrl">
<input type="text" id="search">
</div>
<div class="ng-cloak" >
<div ng-view></div>
</div>
</body>
(ng-controller="MainCtrl" can also be placed on the <body> tag - then the ng-view $scope would be a child of the MainCtrl $scope instead of a sibling.)
Creating the service is as simple as this:
app.factory('Search',function(){
return {text:''};
});
And it's injectable like this:
app.controller('ManageOrderCtrl', function($scope,Search) {
$scope.searchFromService = Search;
});
app.controller('MainCtrl',function($scope,Search){
$scope.search = Search;
});
This way you don't have to rely on sharing data through the global $rootScope (which is kinda like relying on global variables in javascript - a bad idea for all sorts of reasons) or through a $parent scope which may or may not be present.
I've created a plnkr that tries to show the difference between the two solutions.
You can use scope hierarchies.
Add an "outer" ng-controller definition to your HTML like this:
<body ng-controller="MainCtrl">
It will become the $parent scope. But you do not need to share data by using a service. You don't even need to use the $scope.$parent scope. You can use scope hierarchies. (See the Scope Hierarchies section on that page). It is really easy.
In your MainCtrl, you may have this:
$scope.userName = "Aziz";
Then in any controller that is nested within MainCtrl (and does not override the userName in its own scope) will have userName also! You can use in in the view with {{userName}}.
Try this...
View:
<body ng-app="myApp" >
<input type="text" id="search" ng-model="searchQuery" />
<div class="ng-cloak" >
<div ng-view></div>
</div>
</body>
Using it in your controller:
$http.get('/orders?query=' + $scope.searchQuery).
success(function(data, status, headers, config) {
$scope.orders = data.orders;
});
Basically, you can do that with anything INSIDE ng-app... Move your ng-app to the html tag and you can edit the title as well!

AngularJs Model changes don't update

I have a model that I want to be editable, but for some reason nothing change, the textbox doesn't show up and the model is not being updated when using ng-view.
I can see the function enableEditor() being called using console.log.
If I write it inline instead of ng-view in the index.html without the profile.html everything works perfectly.
here are the files:
app.js
var proGamersApp = angular.module('proGamersApp', ['ngResource']).
config(function ($routeProvider) {
$routeProvider.
when('/', { controller: 'ProfileController', templateUrl: '/app/partials/profile.html' }).
otherwise({ redirectTo: '/' });
});
var ProfileController = function ($scope) {
$scope.init = function () {
$scope.title = 'first title';
};
$scope.init();
$scope.enableEditor = function () {
console.log('enableEditor()')
$scope.editorEnabled = true;
$scope.editableTitle = 'second title';
$scope.title = 'second title';
};
...
};
index.html
<!doctype html>
<html ng-app="proGamersApp">
<head>
<title>Pro Gamers</title>
<!-- Scripts -->
<script src="/app/lib/angular.min.js"></script>
<script src="/app/lib/angular-resource.js"></script>
<script src="/app/app.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
profile.html
<div ng-hide="editorEnabled">
{{title}}
Edit title
</div>
<div ng-show="editorEnabled">
<input ng-model="title" ng-show="editorEnabled">
Save
or
cancel.
</div>
Does someone know what I am doing wrong?
thanks
The link is adding to your address, causing the router to refresh the page and wack all your $scope vars. Instead of using blank anchors, use a span styled like an anchor:
span:hover {
cursor:pointer;
}
This only gives the cursor the pointer finger, customize the colors as you wish. Per your comments as well, don't add the target=_self to the href, add it after:
Save //prevent address bar change
As I said before though, use spans instead.

Categories

Resources