AngularJS View Not Updating Using Defer and Factory - angularjs

I am currently having an issue where when I try to create a new setting my view is not being updated until I refresh the page. Can anyone point me into the right direction? If I am going about this the wrong way please let me know a better way to do this.
app.factory('SettingsFactory', function ($http, $q) {
//$scope.settingData = {}
return {
getAllOptionsAsync: function(callback) {
var deferred = $q.defer();
$http.get('/api/settings').success(callback);
},
deleteOptionAsync: function(id) {
//console.log('reached');
var deferred = $q.defer();
$http.delete('/api/settings/' + id);
},
createOptionAsync: function(settingData) {
var deferred = $q.defer();
$http.post('/api/settings', settingData).success(function(data) { console.log(data);
deferred.resolve(data);
// console.log(deferred.promise);
return deferred.promise;
});
}
};
});
var controllers = {};
controllers.SettingsController = function($scope, SettingsFactory) {
//$scope.settings = SettingService.list();
SettingsFactory.getAllOptionsAsync(function(results) {
//console.log(results);
$scope.settings = results;
});
$scope.create = function() {
// console.log('called');
// console.log($scope.formData);
SettingsFactory.createOptionAsync($scope.formData).then(function(data) {
console.log(data);
$scope.settings = data;
});
}
$scope.delete = function(id) {
//console.log(id.entity._id);
SettingsFactory.deleteOptionAsync(id.entity._id);
}
$scope.gridOptions = {
data: 'settings',
multiSelect: false,
columnDefs: [
{field: 'option'},
{field: 'value'},
{displayName: 'Edit', cellTemplate: '<button id="editBtn" type="button" class="btn btn-primary" ng-click="open(settings._id)" >Edit</button> <button id="deleteBtn" type="button" class="btn btn-primary" ng-click="delete(row)" >Edit</button> '}
]
};
}

Inside of the then or anytime you are updating the scope in a callback you need to wrap the $scope.settings=data with a scope.apply.
$scope.$apply(function() {
$scope.settings=data;
});
Typed out on phone so there might be an error.

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);
}
};
}]);

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]);

how to implement ng-model value from another view in ionic

I want to display ng-model value from page to input in another page
I Want display selected issue from issues page to contact page
Issue Controller
.controller('IssueCtrl', function($scope, $http) {
$http.get('api/issues').then(function(resp) {
console.log('Success', resp);
$scope.issues = resp.data;
}, function(err) {
console.error('ERR', err);
$scope.issues = err;
});
})
Contact Controller
.factory('Post', function($resource) {
return $resource('api/add_new_order',{problem: "#problem"});
})
.controller('ContactCtrl', function($scope, Post) {
// Get all posts
$scope.posts = Post.query();
// Our form data for creating a new post with ng-model
$scope.postData = {};
$scope.newPost = function() {
var post = new Post($scope.postData);
post.$save();
}
$scope.issues = {};
$scope.answer = function(){
console.log($scope.issues.name);
}
})
Issue View
<ion-list ng-repeat="item in issues">
<ion-radio ng-model="issues.name" ng-value="'{{item.issue}}'">
{{item.issue}}
</ion-radio>
</ion-list>
Contact View
<form ng-submit="newPost()">
<label class="item item-input">
<span class="input-label">Problem :</span>
<input type="text" name="problem" ng-model="postData.problem">
</label>
</form>
Your API requests should be on independent services, so they can be accessed by any controller.
As you seen to know how a factory works, I will give you an example.
.factory('IssuesService', function($http) {
var issues = [];
return {
all: function() {
return $http.get('api/issues')
.then(function(data){ // Optional callback inside service
issues = data;
});
}
}
})
.controller('ContactCtrl', function($scope, Post, IssuesService) {
...
$scope.issues = [];
IssuesService.all().then(function(data){
$scope.issues = data;
})
...
})
.controller('IssueCtrl', function($scope, $http) {
IssuesService.all()
.then(function(resp) {
console.log('Success', resp);
$scope.issues = resp.data;
}, function(err) {
console.error('ERR', err);
$scope.issues = err;
});
})

Create a simple Bootstrap Yes/No confirmation or just notification alert in AngularJS

It's so simple in a non-Angular environment. Just html and a two line of js code to show a modal confirmation dialog on the screen.
Now I am developting an AngularJS project in which I am using ui-bootstrap modal confirmation dialogs all over the place and I am sick of creating new controllers even for simple things like "Are you sure to delete this record?" kind of stuff.
How do you handle these simple situations? I am sure some people wrote some directives to simplify the needs.
I am asking you to share your experiences or the projects you know about that subject.
so create a reusable service for that... read here
code here:
angular.module('yourModuleName').service('modalService', ['$modal',
// NB: For Angular-bootstrap 0.14.0 or later, use $uibModal above instead of $modal
function ($modal) {
var modalDefaults = {
backdrop: true,
keyboard: true,
modalFade: true,
templateUrl: '/app/partials/modal.html'
};
var modalOptions = {
closeButtonText: 'Close',
actionButtonText: 'OK',
headerText: 'Proceed?',
bodyText: 'Perform this action?'
};
this.showModal = function (customModalDefaults, customModalOptions) {
if (!customModalDefaults) customModalDefaults = {};
customModalDefaults.backdrop = 'static';
return this.show(customModalDefaults, customModalOptions);
};
this.show = function (customModalDefaults, customModalOptions) {
//Create temp objects to work with since we're in a singleton service
var tempModalDefaults = {};
var tempModalOptions = {};
//Map angular-ui modal custom defaults to modal defaults defined in service
angular.extend(tempModalDefaults, modalDefaults, customModalDefaults);
//Map modal.html $scope custom properties to defaults defined in service
angular.extend(tempModalOptions, modalOptions, customModalOptions);
if (!tempModalDefaults.controller) {
tempModalDefaults.controller = function ($scope, $modalInstance) {
$scope.modalOptions = tempModalOptions;
$scope.modalOptions.ok = function (result) {
$modalInstance.close(result);
};
$scope.modalOptions.close = function (result) {
$modalInstance.dismiss('cancel');
};
};
}
return $modal.open(tempModalDefaults).result;
};
}]);
html for display
<div class="modal-header">
<h3>{{modalOptions.headerText}}</h3>
</div>
<div class="modal-body">
<p>{{modalOptions.bodyText}}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn"
data-ng-click="modalOptions.close()">{{modalOptions.closeButtonText}}</button>
<button class="btn btn-primary"
data-ng-click="modalOptions.ok();">{{modalOptions.actionButtonText}}</button>
</div>
once this is done... you just have to inject above service whereever you want to create a dialog box, example below
$scope.deleteCustomer = function () {
var custName = $scope.customer.firstName + ' ' + $scope.customer.lastName;
var modalOptions = {
closeButtonText: 'Cancel',
actionButtonText: 'Delete Customer',
headerText: 'Delete ' + custName + '?',
bodyText: 'Are you sure you want to delete this customer?'
};
modalService.showModal({}, modalOptions)
.then(function (result) {
//your-custom-logic
});
}
You can see my example. whatever i'v done.
<div ng-app="myApp" ng-controller="firstCtrl">
<button ng-click="delete(1);">Delete </button>
</div>
script
var app = angular.module("myApp", []);
app.controller('firstCtrl', ['$scope','$window', function($scope,$window) {
$scope.delete = function(id) {
deleteUser = $window.confirm('Are you sure you want to delete the Ad?');
if(deleteUser){
//Your action will goes here
alert('Yes i want to delete');
}
};
}])
You can use the Angular Confirm library.
When included, it's became available as a directive:
<button type="button" ng-click="delete()" confirm="Are you sure?">Delete</button>
As well as a service:
angular.module('MyApp')
.controller('MyController', function($scope, $confirm) {
$scope.delete = function() {
$confirm({text: 'Are you sure you want to delete?', title: 'Delete it', ok: 'Yes', cancel: 'No'})
.then(function() {
// send delete request...
});
};
});
For anything that has code that is triggered with a ng-click I just add a confirm attribute
eg
<a confirm="Are you sure?" ng-click="..."></a>
and confirm comes from (not mine, found on the web)
app.controller('ConfirmModalController', function($scope, $modalInstance, data) {
$scope.data = angular.copy(data);
$scope.ok = function() {
$modalInstance.close();
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
}).value('$confirmModalDefaults', {
template: '<div class="modal-header"><h3 class="modal-title">Confirm</h3></div><div class="modal-body">{{data.text}}</div><div class="modal-footer"><button class="btn btn-primary" ng-click="ok()">OK</button><button class="btn btn-warning" ng-click="cancel()">Cancel</button></div>',
controller: 'ConfirmModalController'
}).factory('$confirm', function($modal, $confirmModalDefaults) {
return function(data, settings) {
settings = angular.extend($confirmModalDefaults, (settings || {}));
data = data || {};
if ('templateUrl' in settings && 'template' in settings) {
delete settings.template;
}
settings.resolve = { data: function() { return data; } };
return $modal.open(settings).result;
};
})
.directive('confirm', function($confirm) {
return {
priority: 1,
restrict: 'A',
scope: {
confirmIf: "=",
ngClick: '&',
confirm: '#'
},
link: function(scope, element, attrs) {
function reBind(func) {
element.unbind("click").bind("click", function() {
func();
});
}
function bindConfirm() {
$confirm({ text: scope.confirm }).then(scope.ngClick);
}
if ('confirmIf' in attrs) {
scope.$watch('confirmIf', function(newVal) {
if (newVal) {
reBind(bindConfirm);
} else {
reBind(function() {
scope.$apply(scope.ngClick);
});
}
});
} else {
reBind(bindConfirm);
}
}
}
})
My google FOO has failed me and I cannot find the source site for this. I will update if I find it.
You can create a simple factory like this
angular.module('app')
.factory('modalService', [
'$modal', function ($modal) {
var self = this;
var modalInstance = null;
self.open = function (scope, path) {
modalInstance = $modal.open({
templateUrl: path,
scope: scope
});
};
self.close = function () {
modalInstance.dismiss('close');
};
return self;
}
]);
In your controller
angular.module('app').controller('yourController',
['$scope','modalService',function($scope,modalService){
$scope.openModal=function(){
modalService.open($scope,'modal template path goes here');
};
$scope.closeModal=function(){
modalService.close();
//do something on modal close
};
}]);
I have passed $scope in service function so that you can access closeModal function and in case you want to access some data from your controller .
In your html
<button ng-click="openModal()">Open Modal</button>

Property of $scope is not updated on fetching from SQLite with ngCordova

I'm writing an app with Ionic and the $cordovaSQLite plugin. I have this simple controller
.controller('TopicCtrl', ['$scope', '$stateParams', 'Topic', function($scope, $stateParams, Topic) {
$scope.topic = null;
Topic.get($stateParams.topicId).then(function(data) {
$scope.topic = data;
});
}]);
for this simple view
<ion-view view-title="{{topic.title}}">
<ion-content>
...
</ion-content>
</ion-view>
The problem is $scope.topic remains null the first time I display this view (therefore no title for this view is displayed), when I navigate to another view and then press the back button $scope.topic has the fetched data so the topic's title is displayed on the view. Why is $scope.topic not updated as expected?
My services.js looks like this
.factory('SQLiteService', ["$q", "$interval", "$cordovaSQLite", "$ionicPlatform", function($q, $interval, $cordovaSQLite, $ionicPlatform) {
var self = this;
self.db = null;
self.init = function() {
window.plugins.sqlDB.copy("database.db", function () {
self.db = window.sqlitePlugin.openDatabase({name: "database.db", bgType: 1, createFromLocation: 1, location: 2});
}, function (e) {
self.db = window.sqlitePlugin.openDatabase({name: "database.db", bgType: 1, createFromLocation: 1, location: 2});
});
};
self.query = function(query, bindings) {
var wrapper = function() {
bindings = typeof bindings !== 'undefined' ? bindings : [];
var deferred = $q.defer();
$ionicPlatform.ready(function () {
$cordovaSQLite.execute(self.db, query, bindings).then(function(data) {
deferred.resolve(data);
}, function(error) {
deferred.reject(error);
});
});
return deferred.promise;
};
if (!self.db) {
var q = $q.defer();
$interval(function() {
if (self.db) {
q.resolve();
}
}, 100, 25);
return q.promise.then(function() {
return wrapper();
});
}
return wrapper();
};
self.fetch = function(data) {
return data.rows.item(0);
};
return self;
}])
.factory('Topic', ["SQLiteService", function(SQLiteService) {
var self = this;
self.get = function(id) {
var query = "SELECT id, title FROM topics WHERE id = ?";
return SQLiteService.query(query, [id]).then(function(data) {
return SQLiteService.fetch(data);
});
}
return self;
}]);
i had same issue, i solved by using alternative directives for view title as
<ion-view cache-view="false">
<ion-nav-title>{{topic.title}}</ion-nav-title>
<ion-content>
...
</ion-content>
and make sure cache is off for this view

Resources