Angular-Formly: Modal button is not working onChange event - angularjs

I'm trying to popup a modal on onChange event of a formly custom checkbox. Modal turnup okay, but can't make the buttons working :(. Where I'm doing wrong?
{
key: 'coordinatesToLocateSite',
className: 'col-sm-8 col-md-8 col-lg-8',
type: 'custom_checkbox',
templateOptions: {
label: 'Use coordinates to locate site',
onChange: function($viewValue, $modelValue, scope) {
if ($viewValue === true) {
scope.modalInstance = scope.$uibModal.open({
animation: true,
templateUrl: 'address_replace_coordinates_check.html'
})
}
function check() {
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
scope.uncheck = function uncheck(keyName) {
$scope.model[keyName] = !$scope.model[keyName];
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
}
},
expressionProperties: {
'templateOptions.disabled': 'formState.disabled'
}
}
In the template my button are as follows,
<div class="modal-footer">
<button class="btn btn-warning" type="button" ng-click="check()">Ok</button>
<button class="btn btn-primary" type="button" ng-click="uncheck('coordinatesToLocateSite')">Cancel</button>
</div>
And lastly, I've tried the following as well.
formlyConfigProvider.setType({
name: 'custom_checkbox',
templateUrl: 'bcsa_checkbox.html',
wrapper: ['bootstrapHasError'],
apiCheck: function apiCheck(check) {
return {
templateOptions: {
onChange: check.oneOfType([check.string, check.func]),
label: check.string
}
};
},
controller: /* #ngInject */ function($scope, $sce, $uibModal) {
'ngInject';
$scope.$uibModal = $uibModal;
var markerOfRequired = '<span class="red"> \n<strong> \n* \n</strong> \n</span>';
$scope.labelDisplay = $sce.trustAsHtml($scope.to.label + ($scope.to.required ? markerOfRequired : ''));
$scope.onChange = onChange;
$scope.check = check;
$scope.uncheck = uncheck;
function onChange($event) {
if (angular.isString($scope.to.onChange)) {
return $scope.$eval($scope.to.onChange, { $event: $event, $scope: $scope });
} else {
return $scope.to.onChange($event, $scope);
}
}
function check() {
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
function uncheck(keyName) {
$scope.model[keyName] = !$scope.model[keyName];
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
}
});

i couldn't make a fiddle to test on but reading your code i see you'r not calling the functions correctly, the ng-click should access an object defined inside the $scope
so try changing the functions declarations to this
$scope.onChange = function ($event) {
if (angular.isString($scope.to.onChange)) {
return $scope.$eval($scope.to.onChange, { $event: $event, $scope: $scope });
} else {
return $scope.to.onChange($event, $scope);
}
}
$scope.check = function () {
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
$scope.uncheck = function (keyName) {
$scope.model[keyName] = !$scope.model[keyName];
if (scope.modalInstance) {
scope.modalInstance.close();
}
}

I figure it out, when we open the $uibModal we should pass the scope along with that. So, I've modified some codes.
scope.modalInstance = scope.$uibModal.open({
animation: true,
backdrop: false,
keyboard: false,
scope: scope,
templateUrl: 'address_replace_coordinates_check.html'
})
In the controller, instead of accessing scope I've accessed its $parent.
$scope.check = check;
$scope.uncheck = uncheck;
function check() {
let modalInstance = this.$parent.modalInstance;
if (modalInstance) {
modalInstance.close();
}
}
function uncheck(keyName) {
let scope = this.$parent;
let modalInstance = scope.modalInstance;
scope.model[keyName] = !scope.model[keyName];
if (modalInstance) {
modalInstance.close();
}
}

Related

Select Always Returning First Item of List (AngularJS)

No matter what I select, this function only returns the first item of the list. As requested, I have included the complete JS code. I have looked through this code four hours and everything seems right to me. This is my first contact with Angular and any help will be greatly appreciated!
Thank you!
HTML
<div class="form-horizontal input-append">
<select name="selectedSharedTenantId" data-ng-model="selectedSharedTenantId">
<option data-ng-repeat="item in getFilteredTenants()" value="{{item.id}}">{{item.displayName}}</option>
</select>
<button type="button" class="btn" ng-click="addSharedTenant();">
<i class="fas fa-plus"></i>
</button>
</div>
JS
$scope.addSharedTenant = function () {
alert($scope.selectedSharedTenantId)
}
COMPLETE JS CODE
angular.module('directives.datasetEditor', [
'services.dataset',
'ui.bootstrap'
])
.directive('datasetEditor', ['$modal', 'DatasetServices', function ($modal, DatasetServices) {
return {
restrict: 'A',
scope: {
tenantId: '=',
tenants: '=',
originalModel: '=model',
callback: '&callback'
},
link: function(scope, element, attrs) {
scope.model = scope.originalModel ? angular.copy(scope.originalModel) : {
entryType: 'Activity',
displayName: ''
};
var ModalInstanceCtrl = ['$scope', '$modalInstance',
function($scope, $modalInstance) {
var setSelectedSharedTenantId = function () {
var selectedTenant = $scope.getFilteredTenants()[0];
$scope.selectedSharedTenantId = selectedTenant ? selectedTenant.id : null;
};
$scope.getFilteredTenants = function () {
return _.filter($scope.tenants, function (o) {
alert(o.id)
return _.indexOf($scope.model.sharedTenantIds, o.id) == -1 && o.id != $scope.tenantId;
});
};
$scope.getTenantById = function (id) {
return _.findWhere($scope.tenants, {
id: id
});
};
$scope.removedSharedTenant = function (id) {
$scope.model.sharedTenantIds = _.without($scope.model.sharedTenantIds, id);
var selectedTenant = $scope.getFilteredTenants()[0];
setSelectedSharedTenantId();
};
$scope.addSharedTenant = function () {
//alert($scope.selectedSharedTenantId)
//alert($scope.model.sharedTenantIds)
if ($scope.selectedSharedTenantId) {
if ($scope.model.sharedTenantIds == null) {
$scope.model.sharedTenantIds = [];
}
$scope.model.sharedTenantIds.push($scope.selectedSharedTenantId);
setSelectedSharedTenantId();
}
};
$scope.submit = function(isValid) {
if (isValid) {
DatasetServices.save($scope.model).success(function(data, status, headers, config) {
$modalInstance.close(data);
});
} else {
$scope.submitted = true;
}
};
$scope.cancel = function() {
$modalInstance.dismiss();
};
$scope.submitted = false;
setSelectedSharedTenantId();
}];
function open() {
var modalInstance = $modal.open({
templateUrl: '../pkg/wisdom/common/angular/directives/dataset-editor/index.html',
controller: ModalInstanceCtrl,
scope: scope
});
modalInstance.result.then(
function(model) {
scope.callback({
model: model
});
},
function() {
}
);
};
element.on('click', open);
}
};
}]);

Angular Js - select dropdown becomes empty some times on page refresh , why?

i have a simple dropdown which i made with the help of select. The dropdown works fine in normal flow, but when i update my page or sometimes refresh my page the selected value in dropdown becomes empty because of the late response from the backend.
Html
<div class="col-lg-12 col-md-12" ba-panel ba-panel-title="Registration" ba-panel-class="" ng-init="driver.phoneNumberPrefixFunc();">
<div class="col-lg-12 col-md-12" ba-panel ba-panel-title="Registration" ba-panel-class="" ng-init="driver.phoneNumberPrefixFunc();driver.getVehicleTypes();driver.getUnArchBankListing()">
<form class="form-vertical" name="driver.registrationForm" ng-submit="driver.register(driver.registrationInformation);">
<select class="form-control" id="phonePrefix" name="phonePrefix" ng-model="driver.registrationInformation.phoneNumberPrefix"
required>
<option value="" selected>Select Code</option>
<option ng-repeat="item in driver.registrationInformation.phonePrefix" value="{{item.code}}">{{item.code}}</option>
</select>
</form>
</div>
Controller
function editDriverDetails() {
phoneNumberPrefixFunc();
var params = {
id: $stateParams.driverId
};
return driverServices.getDriverDetails(params).then(function (res) {
if (res.success == "1") {
driverData = res.data.driver;
driver.registrationInformation.phoneNumberPrefix = driverData.phoneNumberPrefix;
usSpinnerService.stop('spinner-1');
} else {
usSpinnerService.stop('spinner-1');
toastr.error(res.message, 'Driver');
}
});
};
editDriverDetails function gets called when I am editing my form. As you can see I am calling phoneNumberPrefixFunc() in the beginning as I need the list of phonenumber prefix. below is the function code.
function phoneNumberPrefixFunc(data) {
usSpinnerService.spin('spinner-1');
return driverServices.phoneNumberPrefix(data).then(function (response) {
if (response.success == '1') {
usSpinnerService.stop('spinner-1');
driver.registrationInformation.phonePrefix = response.data.countryCode;
} else {
usSpinnerService.stop('spinner-1');
toastr.error(response.message);
}
});
};
function phoneNumberPrefixFuncwill bring the list of objects in array for dropdown and driver.registrationInformation.phoneNumberPrefix is the preselected value which i get in editDriverDetails function. Now sometimes the response of phoneNumberPrefixFunc or editDriverDetails is late and thats why my drop down does not get populated. How can i fix this ?
I worked it out like this.
Routes.js
(function () {
'use strict';
angular.module('Driver', []).config(routeConfig);
/** #ngInject */
function routeConfig ($stateProvider, $urlRouterProvider) {
function authentication (GlobalServices, $q, localStorageService, $state) {
var d = $q.defer();
var checkUser = localStorageService.get('user');
if (checkUser !== null) {
d.resolve(checkUser);
} else {
GlobalServices.currentUser().then(function (data) {
if (data.success === 0) {
$state.go('login');
} else {
localStorageService.set('user', data.data.account);
d.resolve(data.user);
}
});
}
return d.promise;
}
function phoneNumberPrefix ($q,driverServices) {
var d = $q.defer();
driverServices.phoneNumberPrefix().then(function (data) {
d.resolve(data.data.countryCode);
});
return d.promise;
}
function getVehicleTypes ($q,driverServices) {
var d = $q.defer();
driverServices.vehicleType().then(function (data) {
d.resolve(data.data.vehicleTypes);
});
return d.promise;
}
function getUnArchBankListing ($q,bankServices) {
var d = $q.defer();
bankServices.getUnArchiveBankListing({type : 'unarchive'}).then(function (data) {
d.resolve(data.data.banks);
});
return d.promise;
}
$stateProvider
.state('drivers', {
url: '/drivers',
template: '<ui-view autoscroll="true" autoscroll-body-top></ui-view>',
abstract: true,
// controller: 'DriverMainController',
title: 'Drivers',
sidebarMeta: {
icon: 'fa fa-motorcycle',
order: 3,
},
resolve: {
$user: authentication,
phoneData : function () {},
vehcileTypesData: function () {},
banksData: function () {}
},
})
.state('driverView', {
url: '/driver/:driverId',
templateUrl: '../app/pages/driver/driverView.html',
title: 'Profile',
controller: 'driverCtrl',
controllerAs: 'profile',
resolve: {
$user: authentication,
phoneData : function () {},
vehcileTypesData: function () {},
banksData: function () {}
},
})
.state('driverEdit', {
url: '/driver-edit/:driverId',
params: {
driverDetails: null,
driverId : null
},
templateUrl: '../app/pages/driver/registration/registration.html',
title: 'Driver Profile',
controller: 'driverCtrl',
controllerAs: 'driver',
resolve: {
$user: authentication,
phoneData : function ($q, driverServices) {
var d = $q.defer();
return phoneNumberPrefix($q, driverServices);
},
vehcileTypesData: function ($q, driverServices) {
var d = $q.defer();
return getVehicleTypes($q, driverServices);
},
banksData: function ($q, bankServices) {
var d = $q.defer();
return getUnArchBankListing($q, bankServices);
}
}
});
$urlRouterProvider.when('/drivers', '/drivers/registration');
}
})();
Instead of using ng-init="driver.phoneNumberPrefixFunc();" i made sure that the page only open when the required data is loaded. Then i can access the data in controller like this .
controller.js
(function () {
angular.module('Driver').controller('driverCtrl', driverCtrl);
driverCtrl.$inject = ['$scope', '$state','phoneData','vehcileTypesData','banksData'];
function driverCtrl($scope, $state,phoneData,vehcileTypesData,banksData) {
if(phoneData){
driver.phonePrefix = phoneData;
}
if(banksData){
driver.bankListing = banksData;
}
if(vehcileTypesData){
driver.vehicleTypes = vehcileTypesData;
}
}
})();

Angular JS watch factory variable

I have a factory variable which is shared by two directives. One directives changes it and I need it to update the value in other directive as well.
This is my factory code
commonApp.factory('setSmsMessage', [function () {
var factoryObj = {
data: {
isSms: false
},
setSms: function () {
factoryObj.data.isSms = true;
},
reset: function () {
factoryObj.data.isSms = false;
}
};
return factoryObj;
}]);
This is my one directive
commonApp.directive('osSendMessage', ['setSmsMessage',
function (setSmsMessage) {
return {
restrict: 'A',
scope: {
sent: '='
},
link: function (scope, element, attrs) {
},
controller: function ($scope) {
$scope.setSmsMessage = setSmsMessage.data;
$scope.$watch('setSmsMessage.isSms', function (newValue, oldValue, scope) {
console.log(setSmsMessage.data.isSms);
}, true);
},
templateUrl: "/Static/js/AngularApps/MessageCenter/sendmessage/Templates/sendmessages.html"
};
}]);
This is my other directive which sets the variable
commonApp.directive('osMessageCenterMenu', ['setSmsMessage', function (setSmsMessage) {
return {
restrict: 'A',
scope: {
messages: "="
},
controller: function ($scope) {
},
link: function (scope) {
// opening sms
$("#toggleSendSmsMessage").click(function () {
scope.openSendSms();
});
scope.openSendSms = function () {
console.log("from menu: " + setSmsMessage.data.isSms);
setSmsMessage.setSms();
console.log("from menu: " + setSmsMessage.data.isSms);
$("#SendMessageForm").toggle();
}
// end here
,
templateUrl: "/Static/js/AngularApps/MessageCenter/Templates/messageCenterMenu.html"
};
}]);
But the value is not updated in the other controller which is listening to it
A better way would be to store the isSms property in a global object like so:
commonApp.factory('setSmsMessage', [function ()
{
var factoryObj = {
data: {
isSms: false
},
setSms: function ()
{
factoryObj.data.isSms = true;
},
reset: function ()
{
factoryObj.data.isSms = false;
}
};
return factoryObj;
}]);
Now in your controller link the $scope to the factories global object which holds the isSms property.
// Link setSmsMessage to the factories data object
$scope.setSmsMessage = setSmsMessage.data;
// Now call the setSms() function. The $scope.setSmsMessage will be updated after the call.
setSmsMessage.setSms();
// You can now watch for changes in the $scope like so
$scope.$watch('setSmsMessage.isSms', function (newValue, oldValue, scope) {
console.log(setSmsMessage.data.isSms);
}, true);
Working demo
(function() {
var commonApp = angular.module("app", []);
commonApp.factory('setSmsMessage', [function ()
{
var factoryObj = {
data: {
isSms: false
},
setSms: function ()
{
factoryObj.data.isSms = true;
},
reset: function ()
{
factoryObj.data.isSms = false;
}
};
return factoryObj;
}]);
commonApp.controller("smsController", function($scope, setSmsMessage) {
// Link setSmsMessage to the factories data object
$scope.setSmsMessage = setSmsMessage.data;
// Now call the setSms() function. The $scope.setSmsMessage will be updated after the call.
setSmsMessage.setSms();
$scope.reset = function()
{
setSmsMessage.reset();
}
$scope.$watch('setSmsMessage.isSms', function (newValue, oldValue, scope) {
console.log(setSmsMessage.data.isSms);
}, true);
});
commonApp.directive('osMessageCenterMenu', ['setSmsMessage', function (setSmsMessage)
{
return {
restrict: 'A',
scope: {
messages: "="
},
controller: function ($scope)
{
},
link: function (scope)
{
console.log(scope);
// opening sms
$("#toggleSendSmsMessage").click(function ()
{
scope.openSendSms();
});
scope.openSendSms = function ()
{
console.log("from menu: " + setSmsMessage.data.isSms);
setSmsMessage.setSms();
console.log("from menu: " + setSmsMessage.data.isSms);
$("#SendMessageForm").toggle();
}
}
}
}]);
})()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="smsController">
<div os-message-center-menu>
<button id="toggleSendSmsMessage">reset message</button>
</div>
</div>
</div>
you can also work with $rootScope in your factory and emit an event with custom data and then subscribe to the event in all your controllers
Also, try naming your factory based on functionality, for obvious
reasons.
Following is what am trying to say :-
(function() {
angular
.module("myApp", [])
.factory('smsMessage', ['$rootScope', function($rootScope) {
var factoryObj = {
data: {
isSms: false
},
setSms: function() {
factoryObj.data.isSms = true;
$rootScope.$emit('SET', {isSms : true});
},
reSet: function() {
factoryObj.data.isSms = false;
$rootScope.$emit('RE-SET', {isSms : false});
}
};
return factoryObj;
}])
.controller("controllerOne", function($scope, $rootScope, smsMessage) {
$scope.setSmsMessage = smsMessage.data;
$scope.set = function(){
smsMessage.setSms();
}
$scope.reset = function(){
smsMessage.reSet();
}
$rootScope.$on('SET', function(event, data) {
alert('SET in controllerOne');
$scope.setSmsMessage = data.isSms;
});
$rootScope.$on('RE-SET', function(event, data) {
alert('RE-SET in controllerOne');
$scope.setSmsMessage = data.isSms;
});
})
.controller("controllerTwo", function($scope, $rootScope, smsMessage) {
$scope.setSmsMessage = smsMessage.data;
$scope.set = function(){
smsMessage.setSms();
}
$scope.reset = function(){
smsMessage.reSet();
}
$rootScope.$on('SET', function(event, data) {
alert('SET in controllerTwo');
$scope.setSmsMessage = data.isSms;
});
$rootScope.$on('RE-SET', function(event, data) {
alert('RE-SET in controllerTwo');
$scope.setSmsMessage = data.isSms;
});
});
})()
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="controllerOne">
<label>Controller One</label>
<button ng-click="set()">SET</button>
<button ng-click="reset()">RE-SET</button>
</div>
<div ng-controller="controllerTwo">
<label>Controller Two</label>
<button ng-click="set()">SET</button>
<button ng-click="reset()">RE-SET</button>
</div>
</div>

Modal Factory to be used in place of Confirm()

I have created an Angular Modal factory that passes a couple parameters to create dynamic modals based upon templates and options passed back. However I want to replace all of the Confirm dialogues in my app but am struggling with this.
modal factory
(function () {
var testApp= angular.module('test');
testApp.factory('myModals', ['$uibModal', function ($uibModal) {
// called from various methods within factory
function openModal(template, data, options) {
//build all of the modal options
var modalOpts = {
animation: true,
templateUrl: template,
controller: function ($scope, $uibModalInstance, alert_data) {
$scope.alert_data = alert_data;
$scope.okToProceed = function () {
$scope.goodToGo = true;
console.log("true")
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
console.log("modal cancelled")
};
},
resolve: {
alert_data: data
},
size: '480',
backdrop: 'static'
};
// extend options set in each use type function
if (options) {
angular.extend(modalOpts, modalOpts);
}
var modalInstance = $uibModal.open(modalOpts);
modalInstance.result.then(function (data) {
// always do something when close called
return data;
}, function (data) {
//always do something when dismiss called
return data
});
return modalInstance;
}
function alert(type, text, size) {
var template;
// enter in template and string being passed back to identify modal type
switch (type) {
case 'test1':
template = 'test1.popup.html';
break;
case 'test2':
template = 'test2.popup.html';
break;
}
var opts = {
//default but should be passed back
size: size || 'sm'
};
var data = {
title: type === 'success' ? "OK" : "Error",
text: text
};
return openModal(template, data, opts);
}
return {
alert: alert
}
}])
})();
template.html
<div class="modal-header">
<h3 class="modal-title"></h3>
</div>
<div class="modal-body">
<h3>{{alert_data.text}}</h3>
</div>
<div class="modal-footer">
<button class="btn btn-warning" type="button" ng-click="okToProceed()">Ok</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
example of confirm to be replaced
$scope.discardSource = function(currentIndex) {
if (confirm("Press 'OK' to confirm.")) {
$log.debug("discardDataSource currentIndex: " + currentIndex);
$log.debug($scope.model.dataSamples[currentIndex]);

Directive inside $modal window throws "undefined is not a function"

Using ui-bootstrap I have a really simple custom directive that lists alerts at the top of the page. On normal pages it works like a champ. When I use my directive inside a $modal popup I get "undefined is not a function" at ngRepeatAction.
The directive I have behind the modal on the main page still works. I can see it behind the modal. It's just the one in the modal popup that breaks. What am I doing wrong?
Modal open code:
$modal.open({
templateUrl: 'partials/main/servers/serverAuths/edit.html',
controller: function($scope, $modalInstance) {
$scope.auth = angular.copy(auth);
$scope.auth.password = null;
$scope.saveAuth = function() {
Auths.editAuth($scope.auth).then(
function(resp) {
if (resp.rc===0) {
Alerts.addAlert('success', 'Auth `'+$scope.auth.name+'` saved.');
_.extend(auth, $scope.auth);
$modalInstance.close();
} else {
Alerts.addAlert('danger', 'Auth `'+$scope.auth.name+'` could not be saved. ' + resp.message, 'serverAuths');
}
}
);
};
$scope.resetAuth = function() {
$modalInstance.close();
};
}
}).result.then(
function() {
Auths.getAuthList().then(
function(resp) {
$scope.auths = resp;
}
);
}
);
Directive template:
<div class="alert-wrapper alert-{{ alert.type }}"
ng-repeat="alert in alerts"
ng-class="{ 'relative':relative }">
<div class="container">
<div alert type="alert.type" close="closeAlert($index)">{{alert.msg}}</div>
</div>
</div>
Directive code:
angular.module('app')
.directive('appAlerts', function() {
return {
restrict: 'A',
replace: true,
scope: {
watchForm: '=',
relative: '#'
},
templateUrl: 'partials/directives/appAlerts.html',
controller: function($scope, Alerts) {
$scope.closeAlert = function(idx) { Alerts.closeAlert(idx); };
$scope.alerts = Alerts.getAlerts();
}
};
});
Alerts Factory:
angular.module('app').factory('Alerts', function($timeout) {
var alerts = [];
function timeoutAlert(a) {
$timeout(function() {
a.splice(0, 1);
}, 2500);
}
var addAlert = function(type, msg) {
alerts.push({type:type, msg:msg});
timeoutAlert(alerts);
};
var closeAlert = function(index) {
alerts.splice(index, 1);
};
var getAlerts = function() {
return alerts;
};
var killAlert = function(msg) {
var alert = _.where(alerts, {msg:msg});
var idx = _.indexOf(alerts, alert[0]);
if (idx > -1) {
closeAlert(idx);
}
};
return {
addAlert:addAlert,
closeAlert:closeAlert,
getAlerts:getAlerts,
killAlert:killAlert
};
});

Resources