AngularJS - Pass object data into modal - javascript

I have an information screen in which I'm using a repeater to build out information on a specific user.
When the "Edit" button is clicked, how can I pass the specific user object data into the modal window template?
HTML
<form class="custom" ng-controller="DepCtrl" ng-cloak class="ng-cloak">
<fieldset ng-repeat="object in data.dataset">
<legend><span>{{ object.header }}</span><span class="dep_rel">({{ object.relation }}) </span></legend>
<div class="row">
<div class="four columns" ng-repeat="o in object.collection.inputs">
<span class="table_label">{{ o.label }}:</span><span class="table_answer">{{ o.value }}</span><br>
</div>
</div>
<div class="row">
<a ng-click="openDialog('edit')" style="color:#444;text-decoration:none;margin-right:10px;margin-top:5px;" class="btn_gray smaller left" href="#">Edit</a>
<a style="color:#444;text-decoration:none;margin-top:5px;" class="btn_gray smaller" href="#">Delete</a>
</div>
</fieldset>
</form>
JS
function DepCtrl($scope, Dependents, $dialog) {
$scope.data = Dependents;
var t = '<div class="modal-header">'+
'<h3>' + $scope.header.value + '</h3>'+
'</div>'+
'<div class="modal-body">'+
'<p>Enter a value to pass to <code>close</code> as the result: <input ng-model="result" /></p>'+
'</div>'+
'<div class="modal-footer">'+
'<button ng-click="close(result)" class="btn btn-primary" >Close</button>'+
'</div>';
$scope.opts = {
backdrop: true,
keyboard: true,
dialogFade: true,
backdropClick: false,
template: t, // OR: templateUrl: 'path/to/view.html',
controller: 'TestDialogController'
};
$scope.openDialog = function(action){
var d = $dialog.dialog($scope.opts);
//if (action === 'edit') { $scope.opts.templateUrl = '../../modal.html'; }
d.open().then(function(result){
if(result)
{
alert('dialog closed with result: ' + result);
}
});
};
}

It helps to know which $dialog service you are referring to exactly, since $dialog is not the part of core AngularJS API.
Assuming that you are using the $dialog service from the ui-bootstrap, you can pass your user object into the dialog controller through the resolve property of $dialog configuration object.
As the $dialog documentation states it:
resolve: members that will be resolved and passed to the controller as
locals
function DepCtrl($scope, Dependents, $dialog) {
$scope.data = Dependents;
$scope.opts = {
backdrop: true,
keyboard: true,
dialogFade: true,
backdropClick: false,
template: t, // OR: templateUrl: 'path/to/view.html',
controller: 'TestDialogController',
resolve: {
user: function(){
return $scope.data;
}
}
};
$scope.openDialog = function(action){
var d = $dialog.dialog($scope.opts);
d.open();
};
}
/**
* [TextDialogController description]
* #param {object} $dialog instance
* #param {mixed} user User object from the resolve object
*/
function TextDialogController(dialog, user){
...
}

Related

Angular Modal Text Boxes Not Getting Populated with ngModel

I have a table with TV show data on it. I populate the table with dir-paginate/ng-repeat and I can click a row to open a modal to be able to edit the show but the ng-model data is not loading on the text boxes within that modal.
<tr id='schedule_row' class='hover_click_cell' dir-paginate='tv_show in tv_shows | orderBy:sortType:sortReverse | itemsPerPage:10'>
<td class='center_text clickable_cell cell_width' ng-click='alter_show(tv_show)'>{{tv_show.show_name}}</td>
When clicked, it calls the function alter_show()
$scope.alter_show = function(show)
{
$scope.edit_show = show;
var modalInstance = $uibModal.open ({ animation: $controller.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'edit_tv_show.html',
controller: 'EditTvShowCtrl',
controllerAs: '$controller',
size: 'sm',
backdrop: 'static',
keyboard: false
});
modalInstance.result.then(function (action)
{
},
function () {
});
}
The data passed looks like this in JSON form:
{"watched":false,"id":1,"show_name":"The Walking Dead","season":1,"episode":1,"season_episode":"Season 1, Episode 1","$$hashKey":"object:4"}
I pass in the show details and set it to the $scope.edit_show object. The data being passed on is not empty but when the modal is opened, the text boxes aren't populated. These are the input boxes:
$scope.edit_show = {
show_name: '',
season: 0,
episode: 0,
watched: 0
};
<div class='form-group'>
<label for='show_name'>Show Name:</label>
<input type='text' class='form-control' id='edit_show_name' ng-model='edit_show.show_name'>
</div>
<div class='form-group'>
<label for='season'>Season:</label>
<input type='number' class='form-control' id='edit_season' ng-model='edit_show.season'>
</div>
How can I get this to populate the text box with the details from the row that has been clicked?
I've manage to figure it out using resolve for the modalInstance.
$scope.alter_show = function(show)
{
var modalInstance = $uibModal.open ({ animation: $controller.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'edit_tv_show.html',
controller: 'EditTvShowCtrl',
controllerAs: '$controller',
size: 'sm',
backdrop: 'static',
keyboard: false,
resolve: { tv_show : function() { return show; } }
});
modalInstance.result.then(function (action)
{
},
function () {
});
}
angular.module('ui.bootstrap').controller('EditTvShowCtrl', function ($uibModalInstance, $scope, tv_show)
{
var $controller = this;
$scope.edit = tv_show;
});

Angular uibModal, Resolve, Unknown Provider

I am trying to expose a "generic" modal - using Angular's $uibModal - through a service. Here is the definition of that service:
angular.module('app').service('CustomModalService', ['$uibModal', function ($uibModal) {
var openCustomModal = function (size, title, message) {
var actionToPerformOnConfirm = action;
var modalInstance = $uibModal.open({
templateUrl : 'templates/CustomModal.html',
size: size,
resolve: {
title: title,
message: message
}
});
};
return {
openCustomModal: openCustomModal
};
}]);
Nothing too complicated, above. However, it is not working. If I remove the resolve property from the object, the service works; however, if I include the resolve property, I get the Unknown Provider error originating from that property.
The documentation for the resolve property reads:
(Type: Object) - Members that will be resolved and passed to the
controller as locals; it is equivalent of the resolve property in the
router.
The objective is to be able to provide a template for the modal that utilizes these properties in its DOM, e.g. :
<div ng-controller="CustomModalController">
<div class="modal-header">
<h3 class="modal-title">{{title}}</h3>
</div>
<div class="modal-body">
{{message}}
</div>
<div class="modal-footer">
<button class="ad-button ad-blue" type="button" ng-click="confirmAction()"></button>
<button class="ad-button ad-blue" type="button" ng-click="cancelAction()"></button>
</div>
</div>
What am I missing that is causing this error to be thrown?
You have two problems:
You need to define the controller in your modal config
Your resolve object needs to be a map of string: function, where string is the name of the dependency that will be injected into your modal's controller, and function is a factory function that will be used to provide that dependency when the controller is instantiated.
Working example: JSFiddle
JavaScript
angular.module('myApp', ['ui.bootstrap'])
.controller('MyModalController', MyModalController)
.directive('modalTrigger', modalTriggerDirective)
.factory('$myModal', myModalFactory)
;
function MyModalController($uibModalInstance, items) {
var vm = this;
vm.content = items;
vm.confirm = $uibModalInstance.close;
vm.cancel = $uibModalInstance.dismiss;
};
function modalTriggerDirective($myModal) {
function postLink(scope, iElement, iAttrs) {
function onClick() {
var size = scope.$eval(iAttrs.size) || 'lg'; // default to large size
var title = scope.$eval(iAttrs.title) || 'Default Title';
var message = scope.$eval(iAttrs.message) || 'Default Message';
$myModal.open(size, title, message);
}
iElement.on('click', onClick);
scope.$on('$destroy', function() {
iElement.off('click', onClick);
});
}
return {
link: postLink
};
}
function myModalFactory($uibModal) {
var open = function (size, title, message) {
return $uibModal.open({
controller: 'MyModalController',
controllerAs: 'vm',
templateUrl : 'templates/CustomModal.html',
size: size,
resolve: {
items: function() {
return {
title: title,
message: message
};
}
}
});
};
return {
open: open
};
}
HTML
<script type="text/ng-template" id="templates/CustomModal.html">
<div class="modal-header">
<h3 class="modal-title">{{vm.content.title}}</h3>
</div>
<div class="modal-body">
{{vm.content.message}}
</div>
<div class="modal-footer">
<button class="ad-button ad-blue" type="button" ng-click="vm.confirm()">
confirm
</button>
<button class="ad-button ad-blue" type="button" ng-click="vm.cancel()">
cancel
</button>
</div>
</script>
<button modal-trigger size="'sm'" title="'Hello World!'" message="'This is a test'">
Click Me
</button>

Passing data from ng-Dialog html to controller

have some trouble with ng-Dialog.
When i note ngDialog controller option, it works.
I can get $scope.descriptionText value from
<p>Description:</p>
<textarea ng-model="descriptionText"></textarea>
now i call dialog witout parametr controller
ngDialog.open({
template: 'views/pages/timesheet/template/newEventTemplate.html',
//controller:'newEventDialogCtrl',
scope: $scope,
...
and this value $scope.descriptionText is undefined.
Please help me return values of html element to my controler, or to controller scope.
Dialog call code:
$scope.createNewEventModalWindow = function(args)
{
$scope.setNewEventField('start', args.start.value);
$scope.setNewEventField('end', args.end.value);
ngDialog.open({
template: 'views/pages/timesheet/template/newEventTemplate.html',
//controller:'newEventDialogCtrl',
scope: $scope,
className: 'ngdialog-theme-default',
plain: false,
showClose: true,
closeByDocument: true,
closeByEscape: true,
appendTo: false,
disableAnimation: false,
overlay: false
}).closePromise.then(function(value)
{
console.log('Test msg');
console.log(value);
var newEvent = {
start: $scope.getNewEventField('start'),
end: $scope.getNewEventField('end'),
text: $scope.descriptionText,
userID: getCurrentUserID(),
projectID: $scope.selectedProject,
taskID: $scope.selectedTask
};
console.log('Event data to server');
console.log(newEvent);
/*
TimesheetFactory.createEvent(newEvent)
.success(function(data) {
$scope.events = data;
$scope.message('Event created');
console.log($scope.events);
})
.error(function(data) {
console.log('Error: ' + data);
});
*/
});
}
Html template for dialog:
<div class="ngdialog-message">
<h3>Create Event</h3>
<p>Project</p>
<select id='selectProject' ng-model= "selectedProject">
<option ng-repeat="project in projects" value="{{project.id}}">{{project.name}}</option>
</select>
<p>Task</p>
<select id='selectTask' ng-model="selectedTask">
<option ng-repeat="task in tasks" value="{{task.id}}">{{task.name}}</option>
</select>
<p>Time</p>
<input type="time" id="eventTime" name="input" ng-model="timeLentgh"/>
<p>Description:</p>
<textarea ng-model="descriptionText"></textarea>
</div>
<div class="ngdialog-buttons">
<button
type="button"
class="ngdialog-button ngdialog-button-secondary"
ng-click="closeThisDialog()"
>Cancel</button>
<button
type="button"
class="ngdialog-button ngdialog-button-primary"
ng-click="btnCreateEventClicked()"
>Create</button>
</div>
You can access dialog's scope this way:
value.$dialog.scope()
Where value - argument you get from closePromise.
In this cope you'll have descriptionText for example.
Plunker to check and play: http://plnkr.co/edit/nTNwAxyL1KGuvKGAeTmy?p=preview

Call 2 functions in single ng-click

I am calling two functions on ng-click. But it doesn't work. I am not sure why the Refresh1() is not called when I cross-checked through debugger.
HTML CODE
<div class="row" ng-controller="PublishManifestCtrl">
<div class="col-xs-12 col-md-12">
<div class="widget">
<div class="widget-header bordered-bottom bordered-themeprimary">
<i class="widget-icon fa fa-tasks themeprimary"></i>
<span class="widget-caption themeprimary">Manifest Status</span>
</div>
<div class="widget-body">
<form class="form-bordered" role="form">
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last published to agents on <b>{{manifeststatus.manifestLastPublishedDate}}</b>.</label>
</div>
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last updated by <b> {{manifeststatus.lastUpdatedByUser}} </b> on <b>{{manifeststatus.manifestLastedUpdatedDate}}</b>.</label>
</div>
<div class="form-group">
<div class="col-sm-offset-1">
**<button id="PublishButton" class="btn btn-default shiny " ng-disabled="manifeststatus.enablePublishButton" ng-click="Save(manifeststatus);Refresh1()">Publish</button>**
</div>
<br/>
<div id="statusDivPublish" ng-show="showstatus">
<alert type="{{alert.type}}">{{alert.msg}}</alert>
</div>
</div>
</form>
</div>
JSFILE
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
}
$scope.Refresh1 = function () {
//refresh
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
}
});
new code
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.Refresh1();
}
$scope.Refresh1 = function ($rootScope, $state, $stateParams) {
debugger;
return {
restrict: 'AC',
link: function (scope, el, attr) {
el.on('click', function () {
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
});
}
};
};
});
The first one updates and displays a successfull message, while the second function refreshes the page.
use this
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
call refresh inside the first function and remove it from the ng-click.
Update
You have a different type of problem i had it too. you try to refresh a state inside a method, it's really difficult i solve that problem with this snippet
if($state.current.name == /*name of the current state*/) {
$state.go($state.current, {}, {reload: true});
$modalInstance.close();
}
else {
$modalInstance.close();
$state.go(/*name of the current state*/);
}
it's not difficult but it didn't behave like you have understand it.
UPDATE
taking your code
$scope.Refresh1 = function () {
//refresh
$state.go($state.current, {}, {reload: true});
}
What about calling refresh inside of save in $http handler ?
Like this:
$http.post($rootScope.WebApiURL + '/updatemanifeststatus')
.then(function(){
$scope.Refresh1();
});
Don't execute two function in one ng-click, instead add the Refresh1 call to the end of the Save call, like so.
HTML
<button id="PublishButton"
class="btn btn-default shiny "
ng-disabled="manifeststatus.enablePublishButton"
ng-click="Save(manifeststatus)">Publish</button>
JS
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
Update
If you are using AngularJS V1.2.2 or higher, then using ui-router, the following should work to reload the data.
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
The shortest way to accomplish this though would be with:
$state.go($state.current, {}, {reload: true}); //second parameter is for $stateParams
Its also worth noting that none of these will actually reload the page. If you want to reload the state AND the page, there is no ui-routermethod for it. Do window.location.reload(true)
Update 2
If you are receiving:
$state is not defined at Scope.$scope.Refresh1
(publishmanifest.js:44) at Scope.$scope.Save (publishmanifest.js:37)
at $parseFunctionCall (angular.js:12345) at angular-touch.js:472 at
Scope.$eval (angular.js:14401) at Scope.$apply (angular.js:14500) at
HTMLButtonElement. (angular-touch.js:471) at
HTMLButtonElement.n.event.dispatch (jquery.min.js:3) at
HTMLButtonElement.r.handle (jquery.min.js:3)
You are not injecting the $state service in your controller. You must do this in order to use it.
//without annotation (inferred, not safe when minifying code)
function Controller($scope, $state) {...}
//inline annotation
module.controller('Controller', ['$scope','$state', function($scope, $state) {...}]);
//$inject property annotation
function Controller($scope, $state) {...}
Controller.$inject = ['$scope', '$state'];
Pick one of the methods above to setup your controller to use $state.
Just make a third function like:
function3(data) {
save(data);
refresh1();
}

Cordova Ionic refresh side menu after log in and log out

I'm trying to automatically reload my side menu after I log in and log out. I'm doing that by checking my window.localStorage. I've experienced that the side menu won't reload/refresh after I do the action login or logout.
I'm using $state.go('tabs.home') to navigate to another page, but my side menu won't refresh.
Below here is my code:
navCtrl:
app.controller('NavCtrl', function ($scope, $ionicSideMenuDelegate, $rootScope) {
$scope.showMenu = function () {
$ionicSideMenuDelegate.toggleLeft();
};
$scope.showRightMenu = function () {
$ionicSideMenuDelegate.toggleRight();
};
var data = JSON.parse(window.localStorage.getItem("currentUserData"));
if (data != null) {
if (data["id_gebruiker"] == null) {
$rootScope.control = {
showLogin: false,
showLogout: true
};
}
else {
$rootScope.control = {
showLogin: true,
showLogout: false
};
}
}
})
navHtml:
<ion-side-menu-content ng-controller="NavCtrl">
<ion-nav-bar class="bar-positive">
<ion-nav-back-button class="button-icon ion-arrow-left-c">
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" ng-click="showMenu()">
</button>
</ion-nav-buttons>
<ion-nav-buttons side="right">
<button class="button button-icon button-clear ion-ios7-gear" ng-click="showRightMenu()">
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-nav-view animation="slide-left-right"></ion-nav-view>
</ion-side-menu-content>
loginCtrl:
app.controller('LoginCtrl', function ($scope, $http, $state) {
/*
* This method will be called on click event of button.
* Here we will read the email and password value and call our PHP file.
*/
$scope.check_credentials = function () {
//document.getElementById("message").textContent = "";
$http({ method: 'GET', url: 'http://localhost:34912/api/gebruikers?email=' + $scope.email + '&wachtwoord=' + $scope.wachtwoord }).success(function (data) {
bindUserData(data);
//window.location.reload();
$state.go('tabs.about');
});
function bindUserData(data) {
//alert(JSON.stringify(data));
window.localStorage.setItem("currentUserData", JSON.stringify(data));
}
}
});
app.controller('LogoutCtrl', function ($scope, $http, $state) {
/*
* This method will be called on click event of button.
* Here we will read the email and password value and call our PHP file.
*/
$scope.logout = function () {
var data = JSON.parse(window.localStorage.getItem("currentUserData"));
if (data != null) {
window.localStorage.removeItem("currentUserData");
$state.go('tabs.home');
}
}
});
loginHtml:
<ion-view title="Login">
<ion-content>
<form id="loginForm" ng-app="ionicApp" ng-controller="LoginCtrl">
<div class="list">
<label class="item item-input">
<span class="input-label">Email</span>
<input ng-model="email" type="text" placeholder="Username" />
</label>
<label class="item item-input">
<span class="input-label">Wachtwoord</span>
<input ng-model="wachtwoord" type="password" placeholder="***********" />
</label>
</div>
<div class="padding">
<input type="submit" value="Log on" ng-click="check_credentials()" class="button button-block button-positive" />
</div>
</form>
</ion-content>
I hope you'll understand my problem. I also tried to do a window.location.reload() before $state.go, but that looks buggy. Are there some best practices to fix my problem? Please help me!
Greetings.
Look at the accepted solution at https://stackoverflow.com/a/30524540/1376640
Relevant part of the code is:
$scope.logout = function () {
$ionicLoading.show({
template: 'Logging out....'
});
$localstorage.set('loggin_state', '');
$timeout(function () {
$ionicLoading.hide();
$ionicHistory.clearCache();
$ionicHistory.clearHistory();
$ionicHistory.nextViewOptions({
disableBack: true,
historyRoot: true
});
$state.go('login');
}, 30);
};
Worked for me.
Not a Angular expert but I think that your page will have rebuilt before the $http.get has finished. I got round this by raising an event so where you call bindUserData in the get success change that to $scope.$emit('event', data) then handle the update in a $scope.$on('event'. data). Cut down version of my code below.
controller('AppCtrl', function($scope, $ionicModal, $timeout, MenuData, Data, $ionicActionSheet, UserData, $state, SessionStorage) {
$scope.$on('menuDataChange', function (event, data) {
//refresh menu items data
$scope.items = data;
//clear the state
$state.go($state.current, {}, { reload: true });
});
$scope.items = Data.getItems(SessionStorage.isAuthenticated());
// Form data for the login modal
$scope.loginData = {};
$scope.doLogout = function () {
SessionStorage.clear();
$scope.$emit('menuDataChange', Data.getItems(false)); //Get the menu items for unauthenticated users and raise the change event
};
// Perform the login action when the user submits the login form
$scope.doLogin = function () {
console.log('Doing login', $scope.loginData);
UserData.async($scope.loginData.username, $scope.loginData.password, '12345').then(
// successCallback
function () {
data = UserData.getAll();
var expirationDate = new Date();
expirationDate.setTime(new Date().getTime() + 1200000); //20 minutes
SessionStorage.save({ serverAuthToken: data.d.Items[0].ServerAuthToken, expirationDate: expirationDate });
$scope.$emit('menuDataChange', Data.getItems(true)); //get the menu items for authenticated users and raise the change event
console.log(data);
$state.go('app.home', {}, { reload: true });
},
// errorCallback
function () {
console.log('userdate error');
},
// notifyCallback
function () { }
);
};
})

Categories