I have a simple mdDialog for editing form entries, that pops up when you double-click a grid row. The dialog appears and everything works, except I'd like to populate the fields in the dialog with the contents of the grid row. The problem is that I'm not sure where to actually do this, and every spot I've tried so far is accessed before the Dialog has actually been shown, so the HTML elements inside the dialog don't exist yet to be populated. Here's the method that calls the dialog:
$scope.showUpdateDialog = function(data) {
$mdDialog.show({
controller: UpdateDialogController,
scope: $scope.$new(),
templateUrl: 'js/admin/UpdateUsersDialog.html',
parent: angular.element(document.body),
clickOutsideToClose:true,
fullscreen:true
})
.then(function(answer) {
$scope.status = 'Updated User';
}, function() {
$scope.status = 'Update User Failed';
});
};
And here is the controller for it:
function UpdateDialogController($scope, $mdDialog) {
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
$scope.add = function(dialogdata) {
// For clarity I removed the contents of what happens with the add, as this part works fine.
};
}
Inside that templateUrl: 'js/admin/UpdateUsersDialog.html' are several elements, that all look like this:
<input type="text" class="form-control" id="updatelogin"
placeholder="Enter Name" data-ng-model="dialogdata.login" disabled />
I thought that the data-ng-model bit would take care of it (dialogdata.login etc. are all assigned variables before the dialog is kicked off) but it doesn't, so I was attempting to force it by doing something like this:
var ulogin = document.getElementById('updatelogin');
ulogin.setInnerHTML(content.login);
...but since the elements don't exist yet the 'ulogin' var keeps coming back as null. Is there a way to do this?
Okay after some babbaging I figured something out, maybe this can help others who hit a similar problem. The solution for me was to put everything into the onRowDoubleClicked method, which is called in the ag-grid when I double click a row in the grid:
function onRowDoubleClicked() {
var selectedRowNode = $scope.UserTableGrid.api.getSelectedNodes()[0];
var data = selectedRowNode.data;
$scope.login = data.login;
$scope.name = data.name;
$scope.email = data.email;
$scope.type = data.roles;
$scope.userId = $scope.getUserId($scope.login);
showUDialog(data);
function showUDialog(data) {
$scope.email = data.email;
$mdDialog.show({
controller: UpdateDialogController,
scope: $scope.$new(),
templateUrl: 'js/admin/UpdateUsersDialog.html',
parent: angular.element(document.body),
clickOutsideToClose:true,
fullscreen:true
})
.then(function(answer) {
$scope.status = 'Updated User';
}, function() {
$scope.status = 'Update User Failed';
});
}
function UpdateDialogController($scope, $mdDialog) {
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
$scope.add = function() {
//Close the Dialog
$scope.answer("Completed");
var userJson = {
"name" : $scope.name,
"login" : $scope.login,
"password" : "",
"roles" : $scope.type,
"email" : $scope.email,
"tpbUserId" : $scope.userId
};
var url = 'RobotDataInterface/User/updateUser';
var data = JSON.stringify(userJson);
$http.post(url, data).then(
function success(response) {
$scope.addUserCallback(response);
},
function failure(response) {
$scope.generalRestFailureCallback(response);
}
);
};
$scope.addUserCallback = function(data) {
console.log("User Updated!");
$scope.loadTableData();
}
}
}
This fixed what was a scoping issue, and allowed the fields in the templateUrl to get populated by tying them to those same values:
<input type="text" class="form-control" id="name"
placeholder="Enter Name" data-ng-model="name" />
Related
I got the next controller:
.controller('LogInController', function(logInFactory, $scope, $location, $state){
$scope.logIn = function() {
$scope.dataLoading = true;
logInFactory.logIn($scope.email, $scope.password, function (response) {
if (response.success) {
$scope.userName = response.userName;
console.log('userName', $scope.userName);
logInFactory.setCredentials($scope.email, $scope.password);
$location.path('/users');
} else {
$scope.dataLoading = false;
}
});
};
$scope.clearCredentials = function(){
$state.go('login');
logInFactory.clearCredentials();
};
});//End controller
I want to use it in this view:
<div class="header" ng-controller = 'LogInController'>
<img src= "logo.jpg">
{{userName}}
<button ng-click = 'clearCredentials()'> Cerrar sesión</button>
</div>
But userName is not showing in the view but when I print it on the controller it is displayed correctly. That view is displayed after call the logIn() function.
This is the logIn function in my factory:
var logIn = function(email, password, callback){
var URL;
if(ENV.mocksEnable){
URL = ENV.apiMock + ENV.logInMock;
return (
$timeout(function () {
var response;
getUser()
.then(function (user) {
console.log('USER', user);
if (user !== null) {
response = { success: true, userName: user.userName};
} else {
response = { success: false, message: 'Username or password is incorrect' };
}
callback(response);
});
}, 1000)
);
}else{
URL = ENV.apiURL + ENV.logIn;
return (
$http.post(URL, {email : email, password : password})
.then(function onFulfilled(response){
var data = response.data;
userName = data.username;
userEmail = data.email;
userId = data.id;
profiles = data.profiles;
callback(response);
return data;
})
.catch(function onRejected(errorResponse){
console.log('Error in logInFactory');
console.log('Status: ', errorResponse.status);
callback(errorResponse);
return errorResponse;
})
);
}
};//End login
I trigger the logIn() function in this view
<form ng-submit = 'logIn()'>
<h1>Log In</h1>
Correo electrónico:
<input type="email" ng-model='email' required><br>
Contraseña
<input type="password" ng-model='password' required><br>
<input type="submit" value="Log in">
</form>
When I tigger logIn() I should go to that header and show the userName.
why are you triggering clearCredentials() ? whereas according to this code you should triggering login() instead.
The result of your logIn() function may be out of Angular scope.
Try wrapping the result of the logIn function into a $timeout (which calls $apply, a way to force Angular to refresh a controller scope):
$timeout(function() {
if (response.success) {
$scope.userName = response.userName;
console.log('userName', $scope.userName);
logInFactory.setCredentials($scope.email, $scope.password);
$location.path('/users');
} else {
$scope.dataLoading = false;
}
});
Do not forget to inject the dependency $timeout in your controller.
You have $scope.userName inside the success of the logIn method. It won't be available until that has happened.
If you put $scope.userName outside of the method and set it to something, it would appear.
.controller('LogInController', function(logInFactory, $scope, $location, $state) {
$scope.userName = 'test name';
$scope.logIn = function() { ...
Something like that.
we don't have your factory code but this line is very strange to me :
logInFactory.logIn($scope.email, $scope.password, function (response) { ..; } )
so your passing the fonction to the factory and it is not the factory who returning data to the controller.
it should be something like this :
logInFactory.logIn($scope.email, $scope.password).then(function (response) { ..; } );
EDIT :
You have to remove the callback function from your factory and make the factory return data and handle data like this logInFactory.logIn($scope.email, $scope.password).then(function (response) { ..; } );.
You have log in the console but the $scope is not shared between the factory and controller so the callback in your factory edit the $scope.userName but the controller cannot get this change.
My problem was that I was expecting to get data from a controller to two different views. And when I go from LogIn view to my header view, the controller refresh its data. So, I have to create in my factory:
var getUserName = function() {
return userName;
};
And in the controller
$scope.userName = logInFactory.getUserName();
Now my userName persists in the factory.
I've a following controller code with me :
var app = angular.module('app_name');
app.controller("manageUsersController", [ "config", "$scope", "$http", "$mdToast",
function(config, $scope, $http, $mdToast) {
$scope.add = function() {
var userData = {
email : $scope.manageUsers.email,
password : $scope.manageUsers.password,
schoolId : '1',
name : $scope.manageUsers.name,
mobileNumber : $scope.manageUsers.mobileNumber
};
$http.post(config.webServicesUrl.postAddUser, userData, headerConfig).success(
function(data) {
displayToastMessage("User added successfully", $mdToast);
}).error(function(error) {
console.log(error.error);
});
}
}]);
All the HTML fields are input fields and are accessed using $scope object.
I tried with $setPristine but it didn't work.
Somebody please help me in setting all the fields to empty upon successful submission of form only in my code.
Thanks.
If you want to reset your form upon completion, I think you have to reset the $scope.manageUsers object manually once your post request has resolve:
$http.post(config.webServicesUrl.postAddUser, userData, headerConfig).success(
function(data) {
// has I don't know if you have other properties
// I reset each property manually,
// but you could probably do $scope.manageUsers = {}
$scope.manageUsers.email = null;
$scope.manageUsers.password = null;
$scope.manageUsers.name = null;
$scope.manageUsers.mobileNumber = null;
displayToastMessage("User added successfully", $mdToast);
}).error(function(error) {
console.log(error.error);
});
You can use $setPristine() here:
$http.post(config.webServicesUrl.postAddUser, userData, headerConfig).success(
function(data) {
displayToastMessage("User added successfully", $mdToast);
$scope.form.$setPristine(); // <---------here.
}).error(function(error) {
console.log(error.error);
});
Plnkr demo in action.
It should work for you.
$http.post(config.webServicesUrl.postAddUser,userData,headerConfig)
.success(function(data) {
$scope.manageUsers={};
displayToastMessage("User added successfully.", $mdToast);
}).error(function(error) {
console.log(error.error);
});
Currently I am working on my master project. My application is online portfolio management. User can register on app and create profiles. Now i want to give Edit and Delete buttons on the profile view. But just the users who have created the profile are able to see this buttons. For example, if i am a user of app then only i can see the edit and delete buttons on my profile and i can only see the other user's profile.
I am new in AngularJS. It looks easy but still did not work for me. I have a different views of view profile and edit profile. But i have just one controller for both of it.
This is how my view profile code looks like,
HTML
<section data-ng-controller="ProfilesController as profilesCtrl">
<div class="modal-header">
<div>
<h1>{{profile.firstname}} {{profile.lastname}}</h1>
</div>
<div class="pull-right">
<button class="btn-success btn-lg" type="button" data-ng-click="profilesCtrl.modalUpdate('lg', profile)">Edit</button>
<button class="btn-danger btn-lg" type="button" data-ng-click="profilesCtrl.remove(profile)">
<i class="glyphicon glyphicon-trash">
</i>
</button>
</div>
</div>
</section>
Controller
profilesApp.controller('ProfilesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Profiles', '$modal', '$log',
function($scope, $stateParams, $location, Authentication, Profiles, $modal, $log) {
this.authentication = Authentication;
// Find a list of Profiles
this.profiles = Profiles.query();
// open a modal window to view single profile
this.modalview = function(size, selectedProfile) {
var modalInstance = $modal.open({
templateUrl: 'modules/profiles/views/view-profile.client.view.html',
controller: function($scope, $modalInstance, profile) {
$scope.profile = profile;
console.log(profile);
$scope.ok = function() {
$modalInstance.close($scope.profile);
};
},
size: size,
resolve: {
profile: function() {
return selectedProfile;
}
}
});
modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
// open a modal window to update single profile
this.modalUpdate = function(size, selectedProfile) {
var modalInstance = $modal.open({
templateUrl: 'modules/profiles/views/edit-profile.client.view.html',
controller: function($scope, $modalInstance, profile) {
$scope.profile = profile;
$scope.ok = function() {
$modalInstance.close($scope.profile);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
},
size: size
});
modalInstance.result.then(function(selectedItem) {
$scope.selected = selectedItem;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
// Remove existing Profile
this.remove = function(profile) {
if (profile) {
profile.$remove();
for (var i in this.profiles) {
if (this.profiles[i] === profile) {
this.profiles.splice(i, 1);
}
}
} else {
this.profile.$remove(function() {
$location.path('modules/profiles/views/list-profiles.client.view.html');
});
}
};
// Update existing Profile
this.update = function(updatedProfile) {
var profile = updatedProfile;
profile.$update(function() {}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
}
]);
Please suggest me some way, how can i fix this issue? Any help would appreciated.
you can use a directive like this:
<button access-level="canEdit">Edit</button>
and your directive is bound to accessLevel:
angular.module("app")
.directive('accessLevel', ['AuthService', 'AUTH_EVENTS', function (authService, authEvents) {
return {
restrict: 'A',
link: function ($scope, element, attrs) {
var accessLevel;
attrs.$observe('accessLevel', function (acl) {
if (acl) {
accessLevel = acl;
updateCss();
}
});
$scope.$on("auth-change", function (event, data) {
switch (data) {
case authEvents.logoutSuccess:
case authEvents.loginSuccess:
updateCss();
break;
case authEvents.notAuthorized:
default:
}
});
function updateCss() {
if (accessLevel) {
if (!authService.isAuthorized(accessLevel)) {
switch (element[0].nodeName) {
case "A":
element.hide();
break;
default:
element.attr("disabled", "disabled");
break;
}
} else {
switch (element[0].nodeName) {
case "A":
element.show();
break;
default:
element.removeAttr("disabled");
break;
}
}
}
}
}
}
}]);
this is a little bit more than what you need, but gives you an idea what you can achieve. (and you have to write your auth service etc.)
as example here is a part of my auth service:
angular.module('app')
.factory("AuthService", ["$rootScope", "$http", "AuthSession", "AUTH_EVENTS", function ($rootScope, $http, AuthSession, AUTH_EVENTS) {
AuthSession.load();
$rootScope.$on('$stateChangeStart', function (event, nextState) {
if (nextState.data && nextState.data.accessLevel && !service.isAuthorized(nextState.data.accessLevel)) {
event.preventDefault();
$rootScope.$broadcast('auth-change', AUTH_EVENTS.loginRequired, nextState.name);
}
});
var service = {
login: function (credentials) {
return $http
.post('/api/account/login', credentials)
.success(function (data, status) {
if ((status < 200 || status >= 300) && data.length >= 1) {
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginFailed);
return;
}
AuthSession.create(data.AccessToken, data.User);
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginSuccess);
}).error(function (data, status) {
$rootScope.$broadcast("auth-change", AUTH_EVENTS.loginFailed);
});
},
logout: function () {
AuthSession.destroy();
$rootScope.$broadcast("auth-change", AUTH_EVENTS.logoutSuccess);
},
isAuthenticated: function () {
return (AuthSession.token !== null);
},
isAuthorized: function (accessLevel) {
if (!accessLevel) return true;
return (this.isAuthenticated() && AuthSession.user.UserRoles.indexOf(accessLevel) !== -1);
}
}
return service;
}]);
this service retrieves a bearer token from the server and stores it in the authsession service. the user roles are also stored beside of other user information. since the backend is also secured, one who changes the user roles on the client, can't write to the backend. (everything on client side is just for the look and feel of the user)
Two ways :
Once the profile is created, let the isProfileCreated (you need to make one) column in user details table be updated. On angular load, call and check whether is profile created. use ng-show to show (edit and delete button)if it is true.
Or else, if you are going to edit, anyways you need to get the profile details from the table. in that case, let your server send a false if no profile is created or an json object if created.
In your controller use
if(angular.isObject(profile)){
$scope.showeditbutton = true;
$scope.showdeletebutton = true;
}
In my angular app, i have a message service to display info, loading and error messages for my app. It looks like that:
module.factory('msgSvc', function(){
var current_message = '';
return {
message: function(){
return current_message;
},
setMessage: function(msg){
console.log('setting message: '+ msg);
current_message = msg;
},
clear: function(){ current_message = null; current_style = null}
}
});
and in my view i have
<span class="pull-left label label-warning" >{{ msg.message() }}</span>
I have a login controller, when the user submits the form i want to show a "logging you in..." message while an ajax login is sent. and an error message if there was an error. here's my code:
function LoginCtrl($scope, $http, msgSvc) {
[...]
$scope.login = function(creds) {
console.log(creds);
msgSvc.setMessage('Logging in...');
$http.post('http://...',creds)
.success(function(data){
console.log(data);
[...]
msgSvc.clear();
$location.path('/');
})
.error(function(data, status){
console.log(status);
msgSvc.setMessage('Wrong username or password.');
});
};
}
login() is called by the submit form, Logging in... never shows even though the function is called (it appears in the console). but the error message appears.
am i doing something wrong?
edit: the login form
<form class="form">
<input type="text" placeholder="Username" ng-model="loginCreds.username" required />
<input type="password" placeholder="Password" ng-model="loginCreds.password" required />
<button ng-click="login(loginCreds)">Login</button>
</form>
edit 2
If it changes anything, there are many controllers setting messages in the service and in the actual code, the controller showing the message (where the $scope.msg variable is set) is different from the one setting the message.
function BodyCtrl($scope, msgSvc) {
$scope.msg = msgSvc;
}
There are couple problems with your implementation:
As the message is being set in a private variable, you would need use $watch for the message to be displayed;
A .factory is a singleton and therefore setMessage would have set the same message for all controllers.
The simplest solution is to pass the controller's $scope to the svcMsg:
app.factory("msgSvc", function () {
return function (scope) {
var priv_scope = scope;
this.setMessage = function (msg) {
console.log('setting message: '+ msg);
priv_scope.message = msg;
};
this.clear = function () {
priv_scope.message = "";
};
};
});
In you controller, you would then do:
var msg = new msgSvc($scope);
In case you do want to propagate the message to all controllers, use $rootScope:
app.service("msgSvc", function ($rootScope) {
var priv_scope = $rootScope;
this.setMessage = function (msg) {
console.log('setting message: '+ msg);
priv_scope.message = msg;
};
this.clear = function () {
priv_scope.message = "";
};
});
Check out this Plunker using $rootScope:
http://plnkr.co/edit/NYEABNvjrk8diNTwc3pP?p=preview
As $rootScope is really a global variable in Angular, you shouldn't abuse it. It can also be problematic if you accidentally set the $scope.message in controllers. An alternative is to use $watch to detect the change to the message:
// In your controller, do:
$scope.$watch(
function () {
return msgSvc.message;
},
function () {
$scope.message = msgSvc.message;
}
)
Here is an example using $watch:
http://plnkr.co/edit/vDV2mf?p=info
Set $scope.msg in each place you want to display the value on the view:
function LoginCtrl($scope, $http, msgSvc) {
[...]
$scope.msg = "";
$scope.login = function(creds) {
console.log(creds);
$scope.msg = msgSvc.setMessage('Logging in...');
$http.post('http://...',creds)
.success(function(data){
console.log(data);
[...]
$scope.msg = msgSvc.clear();
$location.path('/');
})
.error(function(data, status){
console.log(status);
$scope.msg = msgSvc.setMessage('Wrong username or password.');
});
};
}
I know you may be trying to avoid that but the changes in its value are not being propagated.
Add $apply to in error()
function LoginCtrl($scope, $http, msgSvc) {
[...]
$scope.login = function(creds) {
console.log(creds);
msgSvc.setMessage('Logging in...');
$scope.msg = msgSvc;
$http.post('http://...',creds)
.success(function(data){
console.log(data);
[...]
msgSvc.clear();
$location.path('/');
})
.error(function(data, status){
$scope.$apply(function() {
msgSvc.setMessage('Wrong username or password.');
});
});
};
}
SEE DEMO
I am building an app with Angular.js accesing the LinkedIn API. What happens is that when I do a call to the API, the model does not get refreshed inmediately, but after I do another change on the screen. For example, I have binded the API call to a button, but I have to press it twice for the screen to get the data refreshed. This is my controller:
angbootApp.controller('AppCtrl', function AppCtrl($scope, $http) {
$scope.getCommitData = function() {
IN.API.Profile("me").fields(
[ "id", "firstName", "lastName", "pictureUrl",
"publicProfileUrl" ]).result(function(result) {
//set the model
$scope.jsondata = result.values[0];
}).error(function(err) {
$scope.error = err;
});
};
});
And this is my button and a link with the content:
<div>
{{jsondata.firstName}}
<form ng-submit="getCommitData()">
<input type="submit" value="Get Data">
</form>
</div>
EDIT: Explanation on how I did it here
You need to call $scope.$apply when retrieving the results/error
angbootApp.controller('AppCtrl', function AppCtrl($scope, $http) {
$scope.getCommitData = function() {
IN.API.Profile("me").fields(
[ "id", "firstName", "lastName", "pictureUrl",
"publicProfileUrl" ]).result(function(result) {
//set the model
$scope.$apply(function() {
$scope.jsondata = result.values[0];
});
}).error(function(err) {
$scope.$apply(function() {
$scope.error = err;
});
});
};
});
Anything outside angular world does not trigger automatic refresh of the views.
See $apply