Angularjs - Controller call init() function multiple times - javascript

I have a problem while I'm making an angularjs app.
I create a controller and bind it in routeProvider. With a function to initialize values for the controller like this.
angular.module('app.Login', ['app.rpc','ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/login', {
templateUrl: '/static/tour/app/login/login.html',
controller: 'loginController'
});
}])
.controller('loginController', function($scope, $location, rpc) {
$scope.init = function() {
$scope.error = "";
console.log("Login Initialized");
}
$scope.init();
});
for login.html like this
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1 class="page-header">Login</h1>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="alert alert-danger alert-dismissable" role="alert" ng-show="error">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<strong>Error: </strong>
<span>{{error}}</span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<form>
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" ng-model="username" placeholder="Username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" ng-model="password" placeholder="Password">
</div>
<button class="btn btn-primary action-btn" ng-click="login()">Login</button>
</form>
</div>
</div>
</div>
When I run the app, it call init() 3 times like this.
login
Find out in this stackoverflow that many people also get this troble. All of them solved by make sure that controller doesn't bind more than one time (in routProvider and in template), and check that only one ng-app in the template.
My main html like this.
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="UTF-8">
<title>Touring</title>
<!--Bootstrap-->
<link rel="stylesheet" href="/static/tour/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/tour/css/bootstrap-theme.min.css">
<!--/Bootstrap-->
</head>
<body>
<ng-view><ng-view>
<!--Angular-->
<script src="/static/tour/js/angular.min.js"></script>
<script src="/static/tour/js/angular-route.min.js"></script>
<script src="/static/tour/js/angular-cookies.min.js"></script>
<!--/Angular-->
<!--App-->
<script src="/static/tour/app/app.js"></script>
<script src="/static/tour/app/rpc/app-rpc.js"></script>
<script src="/static/tour/app/login/app-login.js"></script>
<script src="/static/tour/app/dashboard/app-dashboard.js"></script>
<script src="/static/tour/app/memo/app-memo.js"></script>
</body>
</html>
For my main app like this.
angular.module('app',
['ngCookies',
'ngRoute',
'app.Login',
'app.Dashboard',
'app.Memo',
])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
resolve: {
"check": function($cookies, $location) {
if(!$cookies.get("user_id")) {
$location.path("/login");
}
else {
$location.path("/dashboard");
}
}
}
})
.when('/logout', {
resolve: {
"check": function($cookies, $location) {
if($cookies.get("user_id")){
alert("You have been Logout");
}
$cookies.remove("user_name");
$cookies.remove("user_id");
$cookies.remove("token");
$cookies.remove("dbname");
$location.path("/login");
}
}
});
}]);
It ok for this controller, I just want to initialize a text but it's not ok for init in some controller that need some AJAX request to server side, could make too many request for noting. Anyone can solve this please help me. Thanks.
PS1. My practice base on angular-seed https://github.com/angular/angular-seed
PS2. At first, I also used jquery and it show WARNING: Tried to load angular more than once. Once I remove jquery it never show warning again, but it didn't fix my problem

I already solve it
<ng-view><ng-view>
use this instead
<div ng-view></div>

Concerning your multiple method call, are you sure your current URL is exactly the same as defined in the $routeProvider config? (maybe ngRoute redirects from /login/ to /login and calls your controller twice)
PS2. At first, I also used jquery and it show WARNING: Tried to load angular more than once. Once I remove jquery it never show warning again, but it didn't fix my problem
AngularJS already contains a lite version of jQuery: jqLite. If jQuery is loaded before Angular, this last one will use it. If not, it use the built-in lite version.
In your case, the error is probably due to a jQuery loading after the Angular loading. Angular already loads its version and you load it again.
Try to load jQuery before Angular or do not load it at all.

Related

Angular Submit Syntax and message if no results found using MovieDB API

I'm super new at web development and am trying to learn how to use Angular for a mini project. I'm using The MovieDB's restful API's and all I want to do is a simple search for a movie title, return results that are found, and return a message if nothing is found.
Unfortunately I'm hitting a few comprehension hurdles and I have looked for a solution but haven't found one that matches what I'm doing, which I think is pretty simple (most of the ones I've seen are for more complex approaches and I think it's just beyond my understanding for the moment)
All I want to do right now is have a searchbar, a user types in a movie name, clicks submit, and the angular app will return results. But I can't quite figure out how to pass the submit through to my app. Here is my html code:
<!doctype html>
<html>
<head>
<link
href="http://s3.amazonaws.com/codecademy-content/projects/bootstrap.min.css"
rel="stylesheet" />
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js">
</script>
<!-- Modules -->
<script src="js/app.js"></script>
<!-- Controllers -->
<script src="js/controllers/MainController.js"></script>
<link href="css/main.css" rel="stylesheet" />
</head>
<body ng-app="myApp">
<div class="header">
<img src="img\logo.png"
style="width: 80px; height: 80px;>
<div class="container">
<h1>The MovieDB Search Tool</h1>
<h2>Search for a movie!</h2>
</div>
<div class="main" ng-controller='MainController'>
<div class="searchbar">
<form ng-submit="submitFunction(field)">
<input type="text" name="field" placeholder="Search for a
movie">
<input type="submit" value="Submit">
</form>
</div>
<div class="container">
<div ng-repeat="details in movieList" class="col-md-6">
<div class="thumbnail">
<img ng-
src="https://image.tmdb.org/t/p/w154{{details.poster_path}}">
<p>{{ details.title }}</p>
<p class="date">Release Date: {{ details.release_date | date
}}</p>
<p>{{details.overview}}</p>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="container"></div>
</div>
</body>
</html>
And my javascript code for the angular app:
app.controller('MainController', ['$scope', '$http', function($scope, $http) {
$scope.movieTitle = function submitFunction(field){
}
$http.get('https://api.themoviedb.org/3/search/movie?api_key='+api_key+'&language=en-US&query='
+$scope.movieTitle+'&page=1&include_adult=false')
.then(successCallback, errorCallback);
function successCallback(response){
$scope.movieList = response.data.results
}
function errorCallback(error){
}
}]);
If I plug in a movie name like 'Deadpool' the html works just fine, of course with a static value it runs automatically. And I need it to work on submit, and the way I'm trying isn't working. I would think I need to get a variable passed in to the $scope, buy the submit function but I'm not getting anything when I run this.
If I could get to this point, I think I could figure out the logic to display a message of no results found, it should be as simple as checking the json object the api returns and looking at the "total results" number, then returning a specific message (at least I hope it's that simple).
Any and all help is appreciated!
HTML:
<form ng-submit="submitFunction()">
<input type="text" ng-model="movieTitle" placeholder="Search for a
movie">
<input type="submit" value="Submit">
</form>
CONTROLLER:
app.controller('MainController', ['$scope', '$http', function($scope, $http) {
$scope.submitFunction = function(){
$http.get('https://api.themoviedb.org/3/search/movie?api_key='+api_key+'&language=en-US&query='+$scope.movieTitle+'&page=1&include_adult=false')
.then(successCallback, errorCallback);
}
function successCallback(response){
$scope.movieList = response.data.results
}
function errorCallback(error){
}
}]);

failing to display bootstrap UI Modal

In my AngularJS application I am using the ngIdle module and following the demo that the author has shared on his Github https://hackedbychinese.github.io/ng-idle/.
I have all the right dependencies injected, and all the right CDNs loaded, and the functions are running, but it seems my controllers can't access bootstrap-ui $uibModal.
My CDNs and files are loaded as such:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ng-idle/1.3.2/angular-idle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>
Required modules for both ui-bootstrap and ngIdel are injected as so:
var app = angular.module('myApp', ['ngIdle', 'ui.bootstrap']);
And my controller, which is within an Angular component, also has the required injections as such:
app.component('patents', {
bindings: { patents: '<' },
templateUrl: 'p3sweb/app/components/patents/views/list-patents.htm',
controller: function($state, $scope, Idle, Keepalive, $uibModal) {
$scope.started = false;
function closeModals() {
if ($scope.warning) {
$scope.warning.close();
$scope.warning = null;
}
if ($scope.timedout) {
$scope.timedout.close();
$scope.timedout = null;
}
}
$scope.$on('IdleStart', function() {
closeModals();
$scope.warning = $uibModal.open({
templateUrl: 'warning-dialog.html',
windowClass: 'modal-danger'
});
});
$scope.$on('IdleEnd', function() {
closeModals();
});
});
Question
Why when the functions are running and no errors are being returned, is the modal not opening when the user is Idel? HTML below provided below.
<section>
<p>
<button type="button" class="btn btn-success" ng-hide="started" ng-click="start()">Start Demo</button>
<button type="button" class="btn btn-danger" ng-show="started" ng-click="stop()">Stop Demo</button>
</p>
</section>
<script type="text/ng-template" id="warning-dialog.html">
<div class="modal-header">
<h3>You're Idle. Do Something!</h3>
</div>
<div idle-countdown="countdown" ng-init="countdown=5" class="modal-body">
<uib-progressbar max="5" value="5" animate="false" class="progress-striped active">You'll be logged out in {{countdown}} second(s).</uib-progressbar>
</div>
</script>
<script type="text/ng-template" id="timedout-dialog.html">
<div class="modal-header">
<h3>You've Timed Out!</h3>
</div>
<div class="modal-body">
<p>
You were idle too long. Normally you'd be logged out, but in this demo just do anything and you'll be reset.
</p>
</div>
</script>
You are doing everything fine here except bootstrap css.
I believe you need to include bootstrap 3 CSS
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
because you are using angular ui bootstrap uibModal and its template does include bootstrap 3 classes and including bootstrap 3 css modal popup should work.

"Module 'myapp' is not available" with Bootstraps collapse

I'm getting quite crazy here... I'm trying to use Bootstraps collapse functionality (https://angular-ui.github.io/bootstrap/#/collapse). I'm new to AngularJS. I get the error "Module 'myapp' is not available!". I can't seem to find what's wrong with this code:
<html>
<head></head>
<body>
<script type="text/javascript" src="/js/angular.js"></script>
<script type="text/javascript" src="/js/ui-bootstrap-tpls-0.13.2.min.js"></script>
<script>
angular.module('myapp').controller('CollapseDemoCtrl', function ($scope) {
$scope.isCollapsed = false;
});
</script>
<div ng-app="myapp">
<div ng-controller="CollapseDemoCtrl">
<button type="button" class="btn btn-default" ng-click="isCollapsed = !isCollapsed">Toggle collapse</button>
<hr>
<div collapse="isCollapsed">
<div class="well well-lg">Some content</div>
</div>
</div>
</div>
</body>
</html>
Thank you!
In Angular the syntax for declaring a module is as below, where the modules dependencies are listed in the brackets.
angular.module('myapp', [])
When you want to retrieve a reference to the module, you do this - note how this time the brackets are not used.
angular.module('myapp')
You need to change your code so that it is like this:
angular.module('myapp', []).controller('CollapseDemoCtrl', function ($scope) {
$scope.isCollapsed = false;
});
Plunker here: http://plnkr.co/edit/?p=preview

AngularJS "Controller as" in templates

I am new to AngularJS world and I am trying to setup a basic laravel/angular JWT auth following this tutorial.
What I'd like to do, it's to use the "Controller As" syntax instead of the $scope as stated in the tutorial. For now, here what I have:
app.js
var app = angular.module('app', ['ngRoute']);
app.run(function () {});
app.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/', {
templateUrl: 'js/templates/login.html',
controller: 'LoginController'
});
});
login controller
angular.module('app')
.controller('LoginController', function ($scope) {
this.title='toto';
this.data = {};
this.submit = function () {
console.log(this.data);
};
});
admin view
<!doctype html>
<html lang="en">
<head>
<title>Blog Administration</title>
<!--css-->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"/>
<!--js-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!--angular-->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.4/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.4/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/loginController.js"></script>
</head>
<body ng-app="app">
<div id="wrapper">
<div class="container" id="view" ng-view>
</div>
</div>
</body>
</html>
login template
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body ng-controller="LoginController as login">
<div class="container">
<div id="login" class="col-md-4 col-md-offset-4">
<div id="login-form">
<h4>{{ login.title }}</h4>
<form ng-submit="login.submit()"><!--username-->
<div class="form-group">
<input id="username" type="text" ng-model="login.data.username"/>
</div>
<!--password-->
<div class="form-group">
<input id="password" type="password" ng-model="login.data.password"/>
</div>
<!--submit-->
<div class="form-group">
<button class="btn btn-primary" type="submit">Login</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
The problem is that nothing renders. Is it possible to use a controller per template ?
If I put the <ng-controller="LoginController as login"> directive in the view body instead of template everything renders correctly.
Is it a good practice to define a controller per template ? Because the login template should be as generic as possible, so it can be loaded in any view if the user isn't authenticated, that's why I think putting login() action in the controlelr handling the Admin view is wrong.
Can someone advice me on the best practices to have here ?
In order to use controllerAs syntax with routeProvider you need to declare additional property in route configuration:
$routeProvider.when('/', {
templateUrl: 'js/templates/login.html',
controller: 'LoginController',
controllerAs: 'login'
});
Then you need to clean up login template, removing everything but actual template, e.g. no HTML, body tags, etc. You also don't need extra ngController directive in partial template:
<div id="login" class="col-md-4 col-md-offset-4">
<div id="login-form">
<h4>{{ login.title }}</h4>
<form ng-submit="login.submit()">
<!--username-->
<div class="form-group">
<input id="username" type="text" ng-model="login.data.username" />
</div>
<!--password-->
<div class="form-group">
<input id="password" type="password" ng-model="login.data.password" />
</div>
<!--submit-->
<div class="form-group">
<button class="btn btn-primary" type="submit">Login</button>
</div>
</form>
</div>
</div>
Question 1: Is it possible to use a controller per template ?
Ans: Yes. Its very simply. How, is shown in next answer.
Question 2: Is it a good practice to define a controller per template ?
Ans: As per the AngularJs shown rules, Its good practice. Now see the 2
different way of defining the controller for the template.
a. Directly into the template like: <div ng-controller="myCtrl">Whole template
data goes inside this div.</div>
b. from the app.js where we load the template like this:
.state('app.products.all', {
url: '/all',
templateUrl: 'tpl/products/blocks/thumb.html',
controller: 'ProductsAllCtrl'
})
Here i have also shown the controller with the template path. Second way is
more better then the first.

AngularJS - Route to another page of different ng-app module after login

I have a basic knowledge of AngularJS only. I have created one AngularJS application.
index.html has two links for login and register. With ng-view. By default, login is the view. In the login view I have form. That will be posting to servlet and return the status with object. I have another page home.html wis=ch has its own ng-app module. When the login is success, I want to route to home.html pgae. It also has two links and one ng-view to display the links.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Login - AngularJS</title>
<link rel="stylesheet" type="text/css" media="all" href="styles/angulardemo.css" />
<script src="script/angular.min.js"></script>
<script src="script/app.js"></script>
<script src="script/loginController.js"></script>
</head>
<body data-ng-app="sampleApp">
<div class="index container">
<div class="row">
<div class="">
<ul class="nav">
<li> Login </li>
<li> View1 </li>
</ul>
</div>
<div class="loginView">
<div ng-view></div>
</div>
</div>
</div>
</body>
</html>
login.html
<h2>Login</h2>
<form ng-submit="loginUser()">
<fieldset>
<legend>Login</legend>
<label>Name: </label> <input type="text" id="name" name="name"
ng-model="user.name" placeholder="User Name" required="required">
<br> <label>Password:</label> <input
type="password" id="password" name="password"
ng-model="user.password" placeholder="Your Password"
required="required"> <br>
<button class="btn btn-primary">Login</button>
<br />
</fieldset>
<label>{{user.status}}</label>
</form>
app.js
//Define Routing for app
angular.module('sampleApp', []).config(['$routeProvider',
function($routeProvider,$locationProvider) {
$routeProvider
.when('/login', {
templateUrl: 'login.html',
controller: 'LoginController'
})
.when('/register', {
templateUrl: 'register.html',
controller: 'RegisterController'
})
.otherwise({
redirectTo: '/login'
});
// $locationProvider.html5Mode(true); //Remove the '#' from URL.
}]);
//Home Page Module
angular.module('homeApp', []).config(['$routeProvider',
function($routeProvider,$locationProvider) {
$routeProvider
.when('/home', {
templateUrl: 'home.html'
})
.when('/profile', {
templateUrl: 'profile.html',
controller: 'ProfileController'
})
.when('/settings', {
templateUrl: 'settings.html',
controller: 'SettingsController'
})
.otherwise({
redirectTo: '/home'
});
// $locationProvider.html5Mode(true);
}]);
LoginController (has both login and register. I have implemented only for login)
angular.module('sampleApp').controller('LoginController', function($scope,$location,$http) {
$scope.user = {};
$scope.loginUser = function()
{
$http({
method: 'POST',
url: 'http://localhost:8080/AngularJSLogin/login',
headers: {'Content-Type': 'application/json'},
data: $scope.user
}).success(function (data)
{
var strJSON=data;
if(strJSON.status=="Success")
{
alert("success");
$location.path( "/home" );
}
else
{
$scope.user.status=strJSON.userId+" : "+strJSON.status;
}
});
};
});
angular.module('sampleApp').controller('RegisterController', function($scope,$location,$http) {
$scope.user = {};
});
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Login - AngularJS</title>
<link rel="stylesheet" type="text/css" media="all" href="styles/angulardemo.css" />
<script src="script/angular.min.js"></script>
<script src="script/loginController.js"></script>
<script src="script/userController.js"></script>
</head>
<body data-ng-app="homeApp">
<div class="container">
<div class="row homeTitle">
<div class="username">
<h3>{{user.name}}</h3>
</div>
<div class="homeMenu">
<ul class="nav">
<li> Profile </li>
<li> Settings </li>
</ul>
</div>
</div>
<div class="">
<div ng-view></div>
</div>
</div>
</body>
</html>
Each link has its own controllers.
When I click on the login button with valid username and pasword, It is alerting with Success, but not going to the home (home.html) page.
How can I route to a different page that has different ng-app module from another one? And also how to pass this User object to home.html ng-app module, so it can have user data and display the user name, and other values?
I know this is over 2 years old and i'm sure you might have moved past this but i'm going to tell you how i did as i have a similar set up. Doing everything on the client side wont do it for you. You need to offload some of that routing logic to the server-side. Others might be suggesting using only one ng-app throughout your application but for me that was not a requirement. multi app was a necessity.
My application consisted of 6 ng-apps sharing some common modules and services. each with its own responsibility for e.g I had one like yours with views for login, signup and password-reset while the others were "protected ng-apps".
The trick to get mine working was with the login request. I dont return 200 json back on successful login from the server, I just redirect to the main page i.e I serve the protected main ng-app on successful login. Then i set a httpOnly Cookie with the user information serialized as a JWT String.
Point is...treat every angular application as one page and have your server-side code decide what to show based on your auth rules.
Hope this helps anyone using model :)
We can add many ng-view tags in as many div but it will paste whatever routes mandate to be pasted to the dom.
As I know only one ng-app can be used per html document and same is true for the ng-view also.
The idea I would suggest you to use $routeProvider to navigate between pages in the application.
Use services to have the login information of the user and also have ng-show/ng-hide to show them particular pages based upon their login state.

Categories

Resources