How to prevent this angularjs child component from updating its parent component? In the code below, the instant I update the form in the modal, it updates the parent model as well. This prevents the "cancel" button from working properly.
Here's the plunker showing the issue.
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="//kendo.cdn.telerik.com/2017.1.118/styles/kendo.common.min.css" />
<link rel="stylesheet" href="//kendo.cdn.telerik.com/2017.1.118/styles/kendo.bootstrap.min.css" />
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
<script src="//code.jquery.com/jquery-1.12.4.js"></script>
<script src="//code.angularjs.org/1.5.8/angular.js"></script>
<script src="//kendo.cdn.telerik.com/2017.1.118/js/kendo.all.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.js"></script>
<script id="documents-template" type="text/ng-template">
<button id="openDetails" name="openDetails" ng-click="model.openDetails(1)" class="btn btn-default">Open Details</button>
<pre>{{ model | json }}</pre>
</script>
<script id="details-template" type="text/ng-template">
<div class="modal-body">
<label>Name To Edit</label>
<input ng-model="model.document.title">
<br>
<label>Value To Edit</label>
<input ng-model="model.document.fileName">
<br>
<button class="btn btn-success" type="button" ng-click="model.save()">Save Changes</button>
<button class="btn btn-default" type="button" ng-click="model.cancel()">Cancel</button>
</div>
<pre>{{ model | json }}</pre>
</script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-app="app">
<documents-component></documents-component>
</div>
</body>
</html>
script.js
console.clear();
function documentController($uibModal, TransactionFactory) {
var model = this;
model.transaction = TransactionFactory;
model.openDetails = function(id) {
$uibModal.open({
animation: true,
component: 'detailsComponent',
resolve: {
document: function () {
return model.transaction.documents[id - 1];
}
}
}).result.then(function(result) {
console.log("Save result was:", result);
}, function(reason) {
console.log("Dimissed reason was:", reason);
});
};
}
function detailsController() {
var model = this;
model.document = model.resolve.document;
console.log("model.document", model.document);
model.save = function() {
console.log("saved was clicked. Passing back:", model.document);
model.modalInstance.close(model.document);
};
model.cancel = function() {
model.modalInstance.dismiss("cancel");
};
}
var app = angular.module("app", ["kendo.directives", "ngAnimate", "ui.bootstrap"]);
app.factory('TransactionFactory', function() {
var doc1 = { id:1, title: "Doc1", fileName: "Doc1.pdf" }
var doc2 = { id:2, title: "Doc2", fileName: "Doc2.pdf" }
var doc3 = { id:3, title: "Doc3", fileName: "Doc3.pdf" }
var doc4 = { id:4, title: "Doc4", fileName: "Doc4.pdf" }
var dummyData = [doc1, doc2, doc3, doc4];
console.log("dummyData:", dummyData);
return {
documents: dummyData
};
});
app.component("documentsComponent", {
template: $("#documents-template").html(),
controllerAs: "model",
controller: ["$uibModal", "TransactionFactory", documentController]
});
app.component("detailsComponent", {
template: $("#details-template").html(),
bindings: {
modalInstance: "<",
resolve: '<'
},
controllerAs: "model",
controller: [detailsController]
});
Tried a few changes... basically passing a copy of the required object and only saving (assigning) it when the Save Changes button is clicked.
Your function should be:
model.openDetails = function(id) {
$uibModal.open({
animation: true,
component: 'detailsComponent',
resolve: {
document: function () {
return angular.copy( model.transaction.documents[id - 1] );
}
}
}).result.then(function(result) {
console.log("Save result was:", result);
model.transaction.documents[id - 1] = result ;
}, function(reason) {
console.log("Dimissed reason was:", reason);
});
Try it out
The problem is that in both components you're using reference to the same object with data. So when you edit data in modal you actually edit original object with data which is used also by parent component. Solution is to pass copy of object to your modal.
Refer to the updated plunker https://plnkr.co/edit/cvR8i883Q1ZlPPTA8Ryk?p=preview. you need to pass a copy of object.
function detailsController() {
var model = this;
model.document = angular.copy(model.resolve.document);
console.log("model.document", model.document);
model.save = function() {
console.log("saved was clicked. Passing back:", model.document);
model.modalInstance.close(model.document);
};
model.cancel = function() {
model.modalInstance.dismiss("cancel");
};
}
Related
I have a simple angular controller to post a new name and display the name on the page.
The problem is I cant see the name and the rest of the details to show in the scope ....
Any idea how to fix this and why its not working ?
HTML
<!DOCTYPE html>
<html lang="en" ng-app='myApp'>
<head>
<meta charset="UTF-8">
<title>Angular Base64 Upload Demo</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script type="text/javascript" src="//cdn.rawgit.com/adonespitogo/angular-base64-upload/master/src/angular-base64-upload.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<div ng-controller="UpLoadImage">
<div ng-repeat="step in stepsModel">
<img class="thumb" ng-src="{{step}}"/>
</div>
<label for="file">Select File</label>
<input type='file' name='file' base-sixty-four-input required onload='onLoad' maxsize='600'
accept='image/*' ng-model-instant onchange='angular.element(this).scope().imageUpload(this)'/>
</div>
<div ng-controller="PostData">
{{items.c_name}}
<form ng-submit="sendPost()">
<input ng-model="newName"/>
<button type="submit">Send Data</button>
</form>
</div>
</body>
</html>
App.js
angular.module('myApp', ['naif.base64'])
.controller('UpLoadImage', function ($scope, $http, $window, $rootScope) {
$scope.imageUpload = function (element) {
var reader = new FileReader();
reader.onload = $scope.imageIsLoaded;
reader.readAsDataURL(element.files[0]);
};
$scope.imageIsLoaded = function (e) {
$scope.$apply(function () {
$scope.stepsModel.push(e.target.result);
});
$scope.onLoad = function (e, reader, file, fileList, fileOjects, fileObj) {
alert('image uploaded');
};
};
$scope.stepsModel = [];
})
.controller('PostData', function ($scope, $http) {
$scope.items = {
c_name: "Campaign name here",
max_slots: 5,
slots: [
{
slot_id: 1,
base_image: "base 64 image"
}
]
};
$scope.newName = "Enter name";
$scope.sendPost = function() {
var data = $.param({
json: JSON.stringify({
c_name: $scope.newName
})
});
$http.post("/echo/json/", data).success(function(data, status) {
$scope.items = data;
})
}
});
You missed ng-model property in base-sixty-four-input directive input:
angular.module('myApp', ['naif.base64'])
.controller('UpLoadImage', function ($scope, $http, $window, $rootScope) {
$scope.imageUpload = function (element) {
var reader = new FileReader();
reader.onload = $scope.imageIsLoaded;
reader.readAsDataURL(element.files[0]);
};
$scope.imageIsLoaded = function (e) {
$scope.$apply(function () {
$scope.stepsModel.push(e.target.result);
});
$scope.onLoad = function (e, reader, file, fileList, fileOjects, fileObj) {
alert('image uploaded');
};
};
$scope.stepsModel = [];
})
.controller('PostData', function ($scope, $http) {
$scope.items = {
c_name: "Campaign name here",
max_slots: 5,
slots: [
{
slot_id: 1,
base_image: "base 64 image"
}
]
};
$scope.newName = "Enter name";
$scope.sendPost = function() {
var data = $.param({
json: JSON.stringify({
c_name: $scope.newName
})
});
$http.post("/echo/json/", data).success(function(data, status) {
$scope.items = data;
})
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en" ng-app='myApp'>
<head>
<meta charset="UTF-8">
<title>Angular Base64 Upload Demo</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script type="text/javascript" src="//cdn.rawgit.com/adonespitogo/angular-base64-upload/master/src/angular-base64-upload.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<div ng-controller="UpLoadImage">
<div ng-repeat="step in stepsModel">
<img class="thumb" ng-src="{{step}}"/>
</div>
<label for="file">Select File</label>
<input ng-model="file" type='file' name='file' base-sixty-four-input required onload='onLoad' maxsize='600'
accept='image/*' ng-model-instant onchange='angular.element(this).scope().imageUpload(this)'/>
</div>
<div ng-controller="PostData">
{{items.c_name}}
<form ng-submit="sendPost()">
<input ng-model="newName"/>
<button type="submit">Send Data</button>
</form>
</div>
</body>
</html>
Are you sure property c_name exists on the data returned by the $http.post ? . Add a console log to print what you really get. You also have to ensure there is no error by setting an error callback. I also suggest to give a name other than data for the result (res instead of data for example):
var data = {}; // There is already a variable named data here
$http.post("/echo/json/", data).success(function(res, status) {
$scope.items = res;
console.log("$scope.items: ", $scope.items);
}, function() { console.log("There is an error"); })
Add ng-modal to input where you used base-sixty-four-input directive.
Add cdn path of jquery.
I am trying to set up angular modal service on my web app, but whenever I click on my button it does not appear. What am I doing wrong?
Builder View
<div ng-controller="BuilderController as vm">
<button type="button" class="btn btn-success" ng-click="vm.showExportModal()">Export</button>
</div>
Builder Controller
angular.module('myWebApp')
.controller('BuilderController', function ($scope, BuilderService) {
var vm = this;
vm.showExportModal = function() {
BuilderService.showExportModal();
};
});
Builder Service
angular.module('myWebApp')
.service('BuilderService', function (ModalService) {
var builderService = {
showExportModal: showExportModal
};
return builderService;
function showExportModal() {
ModalService.showModal({
template: "<div>Fry lives in {{futurama.city}}</div>",
controller: function() {
this.city = "New New York";
},
controllerAs : "futurama"
})
};
});
It seems to work fine in this snippet, I suggest checking you have injected it as a dependency in your app.
Please also note you need the correct modal template to display a modal instead of the template you have provided to the directive.
angular.module('myWebApp', ['angularModalService']);
angular.module('myWebApp')
.controller('BuilderController', function($scope, BuilderService) {
var vm = this;
vm.showExportModal = function() {
BuilderService.showExportModal();
};
});
angular.module('myWebApp')
.service('BuilderService', function(ModalService) {
var builderService = {
showExportModal: showExportModal
};
return builderService;
function showExportModal() {
ModalService.showModal({
template: "<div>Fry lives in {{futurama.city}}</div>",
controller: function() {
this.city = "New New York";
},
controllerAs: "futurama"
})
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="http://dwmkerr.github.io/angular-modal-service/angular-
modal-service.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<div ng-app="myWebApp">
<div ng-controller="BuilderController as vm">
<button type="button" class="btn btn-success" ng-click="vm.showExportModal()">Export</button>
</div>
</div>
I am trying to develop an single page web application using angular js. Now when i click a AddFilm button it redirects to the AddNewFilm.html where a message will be displayed and buttons will be hidden in the current view ,for routing i used the $routeProvider, but the problem is when i manually type the url as
http://localhost:8088/fms/#/AddNewFilm it is dispaly the message and also the buttons also.
My question is can we specify the condition in the myApp.config or myApp.controller inorder to route to a url only when an button is clicked.
Welcome.html is
<!doctype html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Film Management System</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="login.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular-route.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="myApp" background='bg1.JPG'>
<img src='bg.png' width="1270" height="222"/>
<div ng-controller="myCtrl">
Add film
Modify Film
Search Film
Remove Film
View All Films
Add Actor
Modify Actor
Search Actor
Remove Actor
View All Actors
Home
<div ng-view></div>
</div>
</body>
</html>
app.js
var myApp = angular.module('myApp', ['ngRoute']);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
myApp.controller('myCtrl', function($scope,$window)
{
$scope.showButtons = function()
{
$scope.action.buttonClicked.addFilm = false
$scope.action.buttonClicked.modifyFilm = false
$scope.action.buttonClicked.searchFilm = false
$scope.action.buttonClicked.removeFilm = false
$scope.action.buttonClicked.getAllFilms = false
$scope.action.buttonClicked.addActor = false
$scope.action.buttonClicked.modifyActor = false
$scope.action.buttonClicked.searchActor = false
$scope.action.buttonClicked.removeActor = false
$scope.action.buttonClicked.getAllActors = false
}
$scope.action =
{
buttonClicked: {},
addFilm: function()
{
$scope.action.buttonClicked.addFilm = true
},
modifyFilm: function()
{
$scope.action.buttonClicked.modifyFilm = true
},
searchFilm: function()
{
$scope.action.buttonClicked.searchFilm = true
},
removeFilm: function()
{
$scope.action.buttonClicked.removeFilm = true
},
getAllFilms: function()
{
$scope.action.buttonClicked.getAllFilms = true
},
addActor: function()
{
$scope.action.buttonClicked.addActor = true
},
modifyActor: function()
{
$scope.action.buttonClicked.modifyActor = true
},
searchActor: function()
{
$scope.action.buttonClicked.searchActor = true
},
removeActor: function()
{
$scope.action.buttonClicked.removeActor = true
},
getAllActors: function()
{
$scope.action.buttonClicked.getAllActors = true
}
}
$scope.message =
{
modifyFilm: 'Hello from ModifyFilm',
addFilm: 'Hello from AddNewFilm',
searchFilm: 'Hello from searchFilm',
removeFilm: 'Hello from removeFilm',
getAllFilms: 'Hello from getAllFilms',
modifyActor: 'Hello from ModifyActor',
addActor: 'Hello from AddNewActor',
searchActor: 'Hello from searchActor',
removeActor: 'Hello from removeActor',
getAllActors: 'Hello from getAllActors'
};
});
myApp.config(function($routeProvider) {
$routeProvider
.when('/AddNewFilm', {
templateUrl : 'AddNewFilm.html',
controller : 'myCtrl'
})
.when('/ModifyFilm', {
templateUrl : 'ModifyFilm.html',
controller : 'myCtrl'
})
.otherwise({redirectTo: '/'});
});
AddNewFilm.html
<div align="center">
<h1>ModifyFilm</h1>
<h3>{{message.addFilm}}</h3>
</div>
can view it at
https://plnkr.co/edit/RXkFAw3Z1ehlt8rJZa5W?p=info
Yes, you just need to redirect to main page, when myCtrl when location is changing and there isn't any clicked button:
myApp.controller('myCtrl', function($scope,$window,$location)
{
// watch for location changing
$scope.$on('$locationChangeStart', function() {
var d = $scope.action.buttonClicked;
// if there isn't any clicked button
if (!Object.keys(d).map(function(k) { return d[k]; }).some(angular.identity)) {
// redirect to main page
$location.url('/');
}
});
...
}
And you shouldn't specify myCtrl as controller in when statement. It's wrong.
Okay so I am trying to learn how to create a modular angular app, but I don't really know how it would look. Based on my code what would I need to do to make it modular? My app is pretty small but I still want to try and get the idea down as for how to create a modular app so that I can just do that from the beginning the next time I create a web app. I didn't include the css as it seems irrelevant for this question. Help would be greatly apprciated.
index.html
<!DOCTYPE html>
<html>
<head>
<header>To do App</header>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>To do App</title>
<script type='text/javascript' src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"> </script>
<script type='text/javascript' src="//use.edgefonts.net/vast-shadow:n4:all.js"></script>
<script type='text/javascript' src="//use.edgefonts.net/vast-shadow:n4:all;megrim.js"></script>
<script type='text/javascript' src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script type='text/javascript' src="js/index.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div ng-app="demoApp">
<script type="text/ng-template" id="partials/edit-form.html">
<div ng-show="todo.editMode">
<input ng-model="todo.text" />
<button ng-click="save(todo)">save</button>
</div>
</script>
<div class="todo-wrapper" ng-controller="todoCtrl">
<h2>You have <span class="emphasis">{{getTotalTodos()}}</span> tasks</h2>
<input class="search-input" type="text" ng-model="searchText" placeholder="enter search term" />
<ul>
<li ng-repeat="todo in todos | filter: searchText">
<span>{{todo.text}}: {{todo.date_created}}</span>
<div ng-include="'partials/edit-form.html'"></div>
<button class="clear-btn" ng-click="removeTask(todo)">Remove</button>
<button class="clear-btn" ng-click="editTask(todo)">Edit</button>
</li>
</ul>
<form>
<input class="add-input" placeholder="task name" type="text" ng-model="text" ng-model-instant />
<button class="add-btn" ng-click="addTask()"><h2>Add</h2></button>
</form>
</div>
</body>
</html>
index.js
angular.module('demoApp', [])
.controller('todoCtrl', TodoCtrl);
function TodoCtrl($scope) {
$scope.todos = [{
id: 1,
text: 'Mow the lawn',
selected: false
}, {
id: 2,
text: 'Wash the car',
selected: false
}];
$scope.id = $scope.todos.length + 1; //later create an uuid
$scope.getTotalTodos = function () {
return $scope.todos.length;
};
$scope.addTask = function () {
$scope.todos.push({
editMode: false,
text: $scope.text,
id: $scope.id,
date_created: Date.now,
selected: false
});
$scope.text = '';
$scope.id = '';
};
$scope.removeTask = function (todo) {
/*$scope.todos = _.filter($scope.todos, function (todo) {
return !todo.selected;
});*/
$scope.todos.pop(todo);
//update server now with ngResource...
};
$scope.showDetails = function (task_id) {
var found = $filter('filter')($scope.todos, {
id: task_id
}, true);
if (found.length) {
$scope.selected = JSON.stringify(found[0]);
} else {
$scope.selected = 'Not found';
}
}
$scope.editTask = function(todo) {
todo.editMode = true;
console.log(todo);
};
$scope.save = function(todo) {
todo.editMode = false;
// update data at server now too. $scope.todos is up-to-date
}
$scope.updateTask = function (task_id) {
// search $scope.todos for the item to update
var indexOfTask;
for (var i = 0; i < $scope.todos.length; i++) {
if ($scope.todos[i].id === $scope.id) indexOfTask = i;
$scope.todos[i] = todo;
$scope.todos.push();
$scope.text = '';
$scope.id = '';
}
// update the todo
};
}
Essentially just make a new file for every angular whatever (factory, controller, directive, etc.)
I use this syntax
angular.module('myapp.functionName.type', [])
.type('functionName',);
Then in your app.js, in your case index.js
angular.module('myapp', ['myapp.functionName.type', ... ]) ;
So I'm running into this problem where I'm using ngView and I have a navigation bar that is static throughout like so:
<div ng-include="'views/nav.html'" ng-controller="NavCtrl"></div>
<div class="container-fluid" ng-view=""></div>
This nav.html, the navigation bar, displays a certain set of functions (Login, Register) if the user is logged out (using ng-show) and other menu options if the user is logged in. Because of the heavy use of current user, I've put this information in the $rootScope like this: $rootScope.currentUser - returns user object, and $rootScope.signedIn - return boolean.
Basically, I want to delay the navbar from loading until $rootScope.signedIn is loaded and either true or false, and $rootScope.currentUser is an object or undefined.
I've tried messing around with creating promises in my app.config routes, but I'm not sure how I can return a promise to the permanent view state.
Any help is appreciated.
Edit:
Here is the service in which I broadcast my login. This fires anytime a user is authenticated/logged in or anytime they logout:
var authClient = new FirebaseSimpleLogin(refDownload, function(error, user) {
if (error) {
incorrectLogin(error.code);
}
if (user) {
// user authenticated
$rootScope.$broadcast('login');
correctLogin(user.id);
} else {
// user is logged out
$rootScope.$broadcast('logout');
}
});
This service is injected into the NavCtrl controller in the following way:
$scope.isHidden = true;
$scope.$on('login', function() {
console.log('login broadcast');
$scope.isHidden = false;
});
$scope.$on('logout', function() {
console.log('broadcast logout');
$scope.isHidden = true;
});
The template for this controller is nav.html that looks like this:
<div class="col-xs-4 centered" id="nav-hover" ng-show="isHidden">
<ul class="nav navbar-nav">
<li id="nav-login"><a ng-href="#/login"><span class="glyphicon glyphicon-log-in"> Login</span></a></li>
</ul>
</div>
<div class="col-xs-4 centered" id="nav-hover" ng-show="isHidden">
<ul class="nav navbar-nav">
<li id="nav-login"><a ng-href="#/register"><span class="glyphicon glyphicon-edit"> Register</span></a></li>
</ul>
</div>
<div class="col-xs-2 centered" id="nav-hover">
<ul class="nav navbar-nav" ng-hide="isHidden">
<li ng-class="{{ chatCat.active }}"><a ng-href="{{ chatCat.url }}"><span class="{{ chatCat.icon }}"></span></a></li>
</ul>
</div>
Again, this view is bound to NavCtrl. When logging users in, I use AuthCtrl as follows:
$scope.login = function() {
if ($scope.user !== undefined) {
Auth.login($scope.user);
$location.path('/dexter');
} else {
console.log('nothing entered');
}
};
When I try to login, the nav view does not update with the new values, although the broadcast is fired from the service with 'logged in'.
Auth service:
'use strict';
app.factory('Auth',
function($rootScope, $location, $firebase, $firebaseSimpleLogin, firebaseUrl) {
var refDownload = new Firebase(firebaseUrl + 'housemates');
var sync = $firebase(refDownload);
var ref = sync.$asObject();
var authClient = new FirebaseSimpleLogin(refDownload, function(error, user) {
if (error) {
incorrectLogin(error.code);
}
if (user) {
// 1
// user authenticated
correctLogin(user.id);
} else {
// user is logged out
// $rootScope.signedIn = false;
}
});
var Auth = {
housemates: ref,
changeColor: function(color) {
var id = $rootScope.currentUser.id.toString();
refDownload.child(id).update({ color: color });
$rootScope.currentUser.color = color;
},
create: function(authUser, usr) {
refDownload.child(authUser.id).set({
initials: usr.initials,
email: authUser.email,
password: usr.password,
color: 'Blue',
id: authUser.id,
uid: authUser.uid,
rememberMe: true,
});
},
// 3
findById: function(id) {
refDownload.on('value', function(snapshot) {
var userObject = snapshot.val();
// 4 - sets currentUser
//$rootScope.currentUser = userObject[id];
var currentUser = userObject[id];
Auth.setUser(currentUser);
// $rootScope.signedIn = true;
}, function (error) {
console.log(error);
});
},
login: function(user) {
authClient.login('password', {
email: user.email,
password: user.password,
rememberMe: true
});
},
logout: function() {
delete $rootScope.currentUser;
delete $rootScope.signedIn;
delete $rootScope.error;
return authClient.logout();
},
register: function(user) {
var userSimple = user;
authClient.createUser(user.email, user.password, function(error, user) {
if(!error) {
var userComplex = user;
Auth.login(userSimple);
Auth.create(userComplex, userSimple);
return user;
} else {
console.log(error);
}
});
},
setUser: function(aUser) {
console.log('setuser ran');
$rootScope.currentUser = aUser;
console.log('setUser: ' + $rootScope.currentUser);
},
isLoggedIn: function() {
console.log($rootScope.currentUser);
return ($rootScope.currentUser) ? $rootScope.currentUser : false;
},
};
// 2
function correctLogin(id) {
Auth.findById(id);
}
function incorrectLogin(error) {
alert(error);
$rootScope.error = error;
}
return Auth;
});
With a bit of $rootScope.$broadcast and ng-hide on the menu, this could be easily accomplished. See this plunker
The html:
<!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.2.x" src="https://code.angularjs.org/1.2.25/angular.js" data-semver="1.2.25"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div ng-include="'nav.html'" ng-controller="NavCtrl" ng-hide="isHidden"></div>
<button class="btn" ng-click="login()">Login</button>
<button class="btn" ng-click="logout()">Logout</button>
</body>
</html>
The javascript:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $rootScope) {
$scope.login = function() {
$rootScope.$broadcast("login");
}
$scope.logout = function() {
$rootScope.$broadcast("logout");
}
});
app.controller('NavCtrl', function($scope) {
$scope.isHidden = true;
$scope.$on('login', function() {
console.log("logged in");
$scope.isHidden = false;
});
$scope.$on('logout', function() {
console.log("logged out");
$scope.isHidden = true;
});
});
OK, if the way i suggested isn't working for you, here is a second possible solution (plunker)
The base idea is to have a service (in this case a factory) in which you set the logged in user name and then in the nav controller use $watch to watch changes to the authentication status in the service. And the code:
<!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.2.x" src="https://code.angularjs.org/1.2.25/angular.js" data-semver="1.2.25"></script>
<script src="app.js"></script>
<script src="Auth.js"></script>
</head>
<body ng-controller="MainCtrl">
<div ng-include="'nav.html'" ng-controller="NavCtrl" ng-hide="isHidden"></div>
<button class="btn" ng-click="login()">Login</button>
<button class="btn" ng-click="logout()">Logout</button>
</body>
</html>
The javascript:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $rootScope, Auth) {
$scope.login = function() {
var user = "iris"
Auth.setUser(user);
}
$scope.logout = function() {
Auth.setUser(null);
}
});
app.controller('NavCtrl', function($scope, Auth) {
$scope.isHidden = true;
$scope.$watch(Auth.isLoggedIn, function (value, oldValue) {
console.log("authentication changed");
if(!value && oldValue) {
console.log("logged out");
$scope.isHidden = true;
}
if(value) {
console.log("logged in");
$scope.isHidden = false;
}
}, true);
});
and the service:
app.factory('Auth', function() {
var user;
return {
setUser: function(aUser) {
user = aUser;
},
isLoggedIn: function() {
console.log(user);
return (user) ? user : false;
}
}
})
#zszep $broadcast answer solved the problem with one caveat. It was necessary to add $scope.$apply() following each of the $scope.isHidden commands in NavCtrl. This forced a page refresh of sorts and the Nav view updated.