Why my service does not share data between controllers? - angularjs

I built a factory to get Data from the Database and pass to all controllers in my application like this:
(function () {
angular.module('appContacts')
.factory('dataService', ['$http', dataService]);
function dataService($http) {
return {
getCurrentOrganization: getCurrentOrganization,
};
function getCurrentOrganization(id) {
return $http({
method: 'GET',
url: '/api/organization/' + id + '/contacts'
})
}
}
})();
And I have a view like this:
<div ng-app="myapp">
<div ng-controller="contactController">
<a ui-sref="organization({Id: organization.id})" ng-click="vm.setCurrentOrganization(organization)"> {{organization.organizationName }}</a>
</div>
</div>
That link redirect from a view the view contactsView.html to a detail view organizationDetail.html managed by a second controller:
....
.state("home", {
url: "/",
templateUrl: "views/contactsView.html",
controller: "contactsController",
controllerAs: "vm"
})
.state("organization", {
url: "/organization/:Id",
templateUrl: "views/organizationDetail.html",
params: { Id: null },
controller: "organizationsController",
controllerAs: "vm"
})
...
My problem is that I get the data, I see in the console, but when the new URL comes into place, the Data is gone and the view is shown empty.
How could I use the data produced in the factory in the second Controller?
EDIT:
Here are the Controllers:
//organizationsController.js
(function () {
"use strict";
angular.module('appContacts')
.controller('organizationsController', function organizationsController(dataService) {
var vm = this;
vm.setCurrentOrganization = function (organization) {
vm.theOrganization = organization;
vm.visible = true;
dataService.getCurrentOrganization(vm.theOrganization.id).then(function (result) {
vm.organizationData = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
}
});
})();
And the contactsController:
//contactsController.js
(function () {
"use strict";
angular.module('appContacts')
.controller('contactsController', function contactsController(dataService) {
var vm = this;
vm.visible = false;
activate();
function activate() {
dataService.getAllContacts().then(function (result) {
vm.allcontacts = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
dataService.getAllOrganizations().then(function (result) {
vm.organizations = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
}
});
})();
The problem is that I click the llink in the view A (contactsView.html/ContactsViewController) and I should end in the VIEW B (OrganizationDetails.html/organizationController), using the Data fetch in the service.

You are doing it wrong here
<div ng-app="myapp">
<div ng-controller="contactController">
<a ui-sref="organization({Id: organization.id})" ng-click="vm.setCurrentOrganization(organization)"> {{organization.organizationName }}</a>
</div>
</div>
Your contactController does not have the function setCurrentOrganization. Instead its in another controller. you can remove the code ng-click="vm.setCurrentOrganization(organization)" from the HTML. and read the id using $stateParams in the organizationsController. After getting the id, use it call the service as below:
dataService.getCurrentOrganization(id).then(function (result) {
vm.organizationData = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});

Related

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

AngularJS: after-select-item not triggering

I am using angularjs version 1.6.4 with angular-multiple-select module for multi selecting. Every thing is working fine. I am able to select from suggestions but whenever i do selection "after-select-item" directive is not triggering. According to angular-multiple-select module documentation
afterSelectItem : Listen for event before adding an item
<div class="form-group float-label-control">
<label>Skills</label>
<multiple-autocomplete ng-model="model.user.skills"
object-property="name"
after-select-item="model.afterSelectItem"
suggestions-arr="model.skills">
</multiple-autocomplete>
</div>
My controller few code lines:
(function () {
"use strict";
var module = angular.module(__appName);
function fetchSkills($http) {
return $http.get(__apiRoot + "/skills")
.then(function (response) {
return response.data;
})
}
function controller($http) {
var model = this;
model.$onInit = function () {
fetchSkills($http).then(function (skills) {
model.skills = skills;
});
};
model.afterSelectItem = function (item) {
console.log("after select item");
console.log(item);
}
}
module.component("userEdit", {
templateUrl: "components/user-edit/user-edit.template.html",
bindings: {
userId: "<",
onUserSaved: "&"
},
controllerAs: "model",
controller: ["$http", controller]
});
}());

AngularJS: Append to url the page number while paginating

I am working on a application where i am paginating through some records by making calls to the server like random/api/endpoint?page=1/2/3
Now i while i paginate,
i need to append the page i am requesting to the url like http://www.paginate.com/somedata/{1/2/3} and on opening this url it should also fetch that specific page in the view {meaning if i navigate to hhtp://www.paginate.com/somedata/4 then the app/view should reflect data from the api call random/api/endpoint?page=4}.
Presently i am using angular-route 1.4.12 with the same version of AngularJS. Very new to angular (2 days), any help will be greatly appreciated.
EDIT : What i want to do ?
When i click next while paginating, it should append the pageNumber to the url.
route.js
angular
.module('mainRouter', ['ngRoute'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/somedata/:page', {
templateUrl: 'partials/somedata.html',
controller: 'PaginationCtrl',
controllerAs: 'vm',
reloadOnSearch: false
}).
otherwise( { redirectTo: "/somedata/1" });
}
]);
PaginationCtrl.js
angular
.module('controllers.Pagination', [])
.controller('PaginationCtrl', PaginationCtrl);
PaginationCtrl.$inject = ['$routeParams', 'paginationService'];
function PaginationCtrl ($routeParams, paginationService) {
var vm = this;
vm.paginationData = {
perPage: 10,
currentPage: 1
};
vm.isLoading = false;
vm.paginate = paginate;
paginate(vm.paginationData.currentPage);
calculateTotalPages();
function calculateTotalPages () {
paginationService.findAll(0, 0)
.success(function (res) {
var paginationData = vm.paginationData || {};
paginationData.totalPages = Math.ceil(res.count / paginationData.perPage);
})
.error(function (res) {
console.log('Error trying to get the total number of pages', res);
});
}
function paginate (pageNumber, perPage) {
vm.isLoading = true;
var paginationData = vm.paginationData || {};
if (! perPage) {
perPage = paginationData.perPage;
}
console.log($routeParams);
paginationService.findAll(perPage, pageNumber)
.success(function (res) {
paginationData.items = res.documents;
vm.isLoading = false;
})
.error(function (res) {
console.log('Error fetching more Logs', res);
});
}
}
PaginationService.js
angular
.module('services.Pagination', [])
.service('paginationService', PaginationService);
PaginationService.$inject = ['$http', 'Constants'];
function PaginationService ($http, Constants) {
// console.log($http);
this.findAll = function (perPage, page) {
var url = Constants.baseUrl + '/sms/get/data';
if (page > 0) {
url += '?page=' + page;
}
return $http.get(url);
};
}
directive being used
var app = angular.module('directives.Pagination', []);
app.directive('pagination', [function () {
return {
restrict: 'E',
template: '<div class="ui pagination menu"> \
<a class="icon item" ng-click="vm.previous()"><i class="left arrow icon"></i></a> \
<div class="icon item">{{ vm.paginationData.currentPage }} / {{ vm.paginationData.totalPages }}</div> \
<a class="icon item" ng-click="vm.next()"><i class="right arrow icon"></i></a> \
</div>',
scope: '=',
link: function (scope, element, attrs) {
var vm = scope.vm;
vm.paginationData.currentPage = 1;
vm.next = function () {
vm.paginationData.currentPage++;
if (vm.paginationData.currentPage > vm.paginationData.totalPages) {
vm.paginationData.currentPage = vm.paginationData.totalPages;
}
vm.paginate(vm.paginationData.currentPage);
};
vm.previous = function () {
vm.paginationData.currentPage--;
if (vm.paginationData.currentPage < 1) {
vm.paginationData.currentPage = 1;
}
vm.paginate(vm.paginationData.currentPage);
};
}
};
}]);
You should be able to access your :page parameter via $routeParams, which you've already injected in your controller.
Just call paginate with $routeParams.page instead of your default of 1.
In order to update the url as you go (in such a way that allows the user to copy the url for later use), without updating the route and re-initializing the controller, you can just call $location.search({page: page}). When this is called with reloadOnSearch set to false (as you've already done) it shouldn't re-initalize the controller.
Lastly, in case its not clear, you'll have to update the URL at the same time you make your API call. There isn't a built in angular way to do this, but it should be pretty straightforward.

Passing data in master detail view in Ionic using this (NOT Scope)?

UPDATE
The service seem to be fetching data but when the data is sent to controller, it is undefined. Adding the service.js file for reference as well
service.js
.service('VideosModel', function ($http, Backand) {
var service = this,
baseUrl = '/1/objects/',
objectName = 'videos/';
function getUrl() {
return Backand.getApiUrl() + baseUrl + objectName;
}
function getUrlForId(id) {
return getUrl() + id;
}
service.all = function () {
console.log($http.get(getUrl()));
return $http.get(getUrl());
};
service.fetch = function (id) {
console.log('Inside s');
console.log($http.get(getUrlForId(id)));
return $http.get(getUrlForId(id));
};
service.create = function (object) {
return $http.post(getUrl(), object);
};
service.update = function (id, object) {
return $http.put(getUrlForId(id), object);
};
service.delete = function (id) {
return $http.delete(getUrlForId(id));
};
})
Pic
I am trying to implement the master-detail view on one of the tabs in my app using this instead of scope (example using scope here). But my details view is not getting the data/ it is saying undefined for detailsCtrl. I believe I'm making a mistake in my controller or app.js but I don't really have an idea about how to fix it.
master.html
<ion-view view-title="Videos">
<div ng-if="!vm.isCreating && !vm.isEditing">
<ion-content class="padding has-header">
<!-- LIST -->
<div class="row gallery">
<div class="list card col col-25" ng-repeat="object in vm.data"
ng-class="{'active':vm.isCurrent(object.id)}">
<a class="cardclick" href="#/details/{{object.id}}">
<div class="item item-image">
<img ng-src="{{object.img}}"/>
</div>
<div class="item item-icon-left assertive">
<i class="icon ion-play"></i>
<p> Watch</p>
<h2> {{object.title}} </h2>
</div>
</a>
</div>
</div>
</ion-content>
</div>
details view or videoplayer.html
<ion-view title="Now Playing" hide-nav-bar="true">
<div class="modal transparent fullscreen-player">
<video src="{{object.src}}" class="centerme" controls="controls" autoplay></video>
</div>
app.js
$stateProvider
// setup an abstract state for the tabs directive
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginCtrl as login'
})
.state('forgotpassword', {
url: '/forgot-password',
templateUrl: 'templates/forgot-password.html',
})
.state('tab', {
url: '/tabs',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('tab.videos', {
url: '/videos',
views: {
'tab-videos': {
templateUrl: 'templates/tab-videos.html',
controller: 'VideosCtrl as vm'
}
}
})
.state('tab.games', {
url: '/games',
views: {
'tab-games': {
templateUrl: 'templates/tab-games.html'
}
}
})
.state('tab.help', {
url: '/help',
views: {
'tab-help': {
templateUrl: 'templates/tab-help.html'
}
}
})
.state('details', {
url: "/details/:id",
templateUrl: 'templates/videoplayer.html',
controller: 'detailsCtrl as vm'
});
$urlRouterProvider.otherwise('/login');
$httpProvider.interceptors.push('APIInterceptor');
})
controller
.controller('VideosCtrl', function (VideosModel, $rootScope) {
var vm = this;
function goToBackand() {
window.location = 'http://docs.backand.com';
}
function getAll() {
vm.data=[];
VideosModel.all()
.then(function (result) {
vm.data = result.data.data;
console.log(vm.data);
});
}
function initCreateForm() {
vm.newObject = {name: '', description: ''};
}
function setEdited(object) {
vm.edited = angular.copy(object);
vm.isEditing = true;
}
function isCurrent(id) {
return vm.edited !== null && vm.edited.id === id;
}
function cancelEditing() {
vm.edited = null;
vm.isEditing = false;
}
function cancelCreate() {
initCreateForm();
vm.isCreating = false;
}
function clearData(){
vm.data = null;
}
function create(object) {
VideosModel.create(object)
.then(function (result) {
cancelCreate();
getAll();
});
}
function update(object) {
VideosModel.update(object.id, object)
.then(function (result) {
cancelEditing();
getAll();
});
}
function deleteObject(id) {
VideosModel.delete(id)
.then(function (result) {
cancelEditing();
getAll();
});
}
vm.edited = null;
vm.isEditing = false;
vm.isCreating = false;
vm.getAll = getAll;
vm.create = create;
vm.update = update;
vm.delete = deleteObject;
vm.setEdited = setEdited;
vm.isCurrent = isCurrent;
vm.cancelEditing = cancelEditing;
vm.cancelCreate = cancelCreate;
vm.goToBackand = goToBackand;
vm.isAuthorized = false;
$rootScope.$on('authorized', function () {
vm.isAuthorized = true;
getAll();
});
$rootScope.$on('logout', function () {
clearData();
});
if(!vm.isAuthorized){
$rootScope.$broadcast('logout');
}
initCreateForm();
getAll();
})
.controller('detailsCtrl',function($stateParams,VideosModel){
var vm = this;
var videoId = $stateParams.id;
function getforId(id) {
vm.data=[];
VideosModel.fetch(id)
.then(function (result) {
vm.data = result.data.data;
console.log(vm.data);
});
}
getforId(videoId);
});
How do pass the data using this?
In order to use controllerAs syntax (bind your scope properties to 'this' in the controller) you need to give your controller an alias in the html.
<div ng-controller="detailsCtrl as vm">
By default, your html is going to reference $scope on your controller unless you give it an alias.
https://docs.angularjs.org/api/ng/directive/ngController

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