I got this template:
<ion-view view-title="MAP" name="tab-map">
<ion-content has-tabs="true" style="text-align:center;">
<div style="width:100%;height:400px;" ng-attr-id="{{'canvas_map_'+place.id}}"></div>
</ion-content>
</ion-view>
and I'm trying to set div's content dynamically by passing through controller:
angular.module('helloDynamicMap', ['ionic'])
.config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
$ionicConfigProvider.navBar.alignTitle('center');
$ionicConfigProvider.tabs.position('bottom');
$ionicConfigProvider.backButton.text('').icon('ion-chevron-left');
$ionicConfigProvider.backButton.previousTitleText(false);
$stateProvider
.state('main', {
url: "/main",
controller: "PlacesCtrl",
//abstract: true,
templateUrl: 'templates/main.html',
resolve: {
resultPlaces: function (findPlace, $stateParams) {
return findPlace.all();
}
}
})
.state('place', {
url: "/place/:placeId",
//abstract: true,
templateUrl: 'templates/place-tabs.html',
controller: 'PlaceCtrl',
resolve: {
resultPlace: function (findPlace, $stateParams) {
return findPlace.get($stateParams.placeId);
}
}
})
.state('place.details', {
url: '/details',
views: {
'tab-details': {
templateUrl: 'templates/details.html'
},
}
})
.state('place.map', {
url: '/map',
views: {
'tab-map': {
templateUrl: 'templates/map.html' //,
//controller: "MapCtrl"
}
}
});
$urlRouterProvider.otherwise("/main");
})
.controller('AppCtrl', function ($scope, $state, $rootScope) {
// button back
$scope.goBack = function () {
console.log("back button");
$state.go("main");
}
})
.controller('PlacesCtrl', function ($scope, $rootScope, $state, resultPlaces) {
// Get places
$scope.places = resultPlaces;
// Button back
$scope.goTabs = function () {
$state.go("tab.map");
}
})
.controller('PlaceCtrl', function ($scope, $rootScope, $state, resultPlace) {
// Load place's data in scope's model
$scope.place = resultPlace;
var div = document.getElementById("canvas_map_" + resultPlace.id);
console.log("div", div);
// Create Map
var map;
document.addEventListener("deviceready", function () {
var div = document.getElementById("canvas_map_" + resultPlace.id);
// Initialize the map view
map = plugin.google.maps.Map.getMap(div);
// Wait until the map is ready status.
map.addEventListener(plugin.google.maps.event.MAP_READY, onMapReady);
}, false);
function onMapReady() {
var button = document.getElementById("button_" + resultPlace.id);
button.addEventListener("click", onBtnClicked, false);
}
function onBtnClicked() {
map.showDialog();
}
})
.factory('findPlace', function ($q) {
// list all places
var places = [];
places = [{
id: "1",
name: "Place A",
details: "details for Place A",
latitude: "28.472143",
longitude: "-81.469856"
}, {
id: "2",
name: "Place B",
details: "details for Place B",
latitude: "",
longitude: ""
}, {
id: "3",
name: "Place C",
details: "details for Place C",
latitude: "",
longitude: ""
}];
return {
all: function () {
var dfd = $q.defer();
// resolve promise
dfd.resolve(places);
// return promise
return dfd.promise;
},
get: function (placeId) {
for (var i = 0; i < places.length; i++) {
if (places[i].id == parseInt(placeId)) {
return places[i];
}
}
return null;
}
}
})
This code works perfectly when I use static id name as "canvas_map_01", but doesn't works when I tries to set it through scope variables.
The main question is how to set and handle div elements through dynamic id name:
// Load place's data in scope's model
$scope.place = resultPlace;
var div = document.getElementById("canvas_map_" + resultPlace.id);
console.log("div", div);
My full code is on Github, please somebody can tell me what am I doing wrong?
-Change your html from
ng-attr-id="{{'canvas_map_'+place.id}}"
To
id="{{'canvas_map_'+place.id}}"
-Change your code from
var div = document.getElementById("canvas_map_" + resultPlace.id);
To
var div = angular.element("#canvas_map_" + resultPlace.id);
Than it will work fine
Related
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;
}
}
})();
I'm trying to cleanup code of one of my controllers which became too big. First I have decided to move attendee registration, which uses AngularJS Material mdDialog, to the service.
Original (and working) controller code looks like:
myApp.controller('RegistrationController', ['$scope','$routeParams','$rootScope','$location','$filter','$mdDialog', function($scope, $routeParams, $rootScope, $location, $filter, $mdDialog){
var attendee = this;
attendees = [];
...
$scope.addAttendee = function(ev) {
$mdDialog.show({
controller: DialogController,
templateUrl: 'views/regForm.tmpl.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose:true,
controllerAs: 'attendee',
fullscreen: $scope.customFullscreen, // Only for -xs, -sm breakpoints.
locals: {parent: $scope}
})
.then(function(response){
attendees.push(response);
console.log(attendees);
console.log(attendees.length);
})
};
function DialogController($scope, $mdDialog) {
var attendee = this;
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.save = function(response) {
$mdDialog.hide(response);
};
}
}]);
and the code for the controller after separation:
myApp.controller('RegistrationController', ['$scope','$routeParams','$rootScope','$location','$filter','$mdDialog','Attendees', function($scope, $routeParams, $rootScope, $location, $filter, $mdDialog, Attendees){
...
$scope.attendees= Attendees.list();
$scope.addAttendee = function (ev) {
Attendees.add(ev);
}
$scope.deleteAttendee = function (id) {
Attendees.delete(id);
}
}]);
New service code looks like:
myApp.service('Attendees', ['$mdDialog', function ($mdDialog) {
//to create unique attendee id
var uid = 1;
//attendees array to hold list of all attendees
var attendees = [{
id: 0,
firstName: "",
lastName: "",
email: "",
phone: ""
}];
//add method create a new attendee
this.add = function(ev) {
$mdDialog.show({
controller: DialogController,
templateUrl: 'views/regForm.tmpl.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose:true,
controllerAs: 'attendee',
fullscreen: this.customFullscreen, // Only for -xs, -sm breakpoints.
//locals: {parent: $scope}
})
.then(function(response){
attendees.push(response);
console.log(attendees);
console.log(attendees.length);
})
};
//simply search attendees list for given id
//and returns the attendee object if found
this.get = function (id) {
for (i in attendees) {
if (attendees[i].id == id) {
return attendees[i];
}
}
}
//iterate through attendees list and delete
//attendee if found
this.delete = function (id) {
for (i in attendees) {
if (attendees[i].id == id) {
attendees.splice(i, 1);
}
}
}
//simply returns the attendees list
this.list = function () {
return attendees;
}
function DialogController($mdDialog) {
this.hide = function() {
$mdDialog.hide();
};
this.cancel = function() {
$mdDialog.cancel();
};
this.save = function(response) {
$mdDialog.hide(response);
};
}
}]);
but I'm not able to "save" from the spawned mdDialog box which uses ng-click=save(attendee) neither close the dialog box.
What I'm doing wrong?
I'm not able to "save" from the spawned mdDialog box which uses ng-click=save(attendee) neither close the dialog box.
When instantiating a controller with "controllerAs" syntax, use the name with which it is instantiated:
<button ng-click="ctrl.save(ctrl.attendee)">Save</button>
this.add = function(ev) {
$mdDialog.show({
controller: DialogController,
templateUrl: 'views/regForm.tmpl.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose:true,
controllerAs: ̶'̶a̶t̶t̶e̶n̶d̶e̶e̶'̶ 'ctrl',
fullscreen: this.customFullscreen, // Only for -xs, -sm breakpoints.
//locals: {parent: $scope}
})
.then(function(response){
attendees.push(response);
console.log(attendees);
console.log(attendees.length);
return response;
});
To avoid confusion, choose a controller instance name that is different from the data names.
$scope is not available to be injected into a service when it's created. You need to refactor the service and its methods so that you don't inject $scope into it and instead pass the current scope to the service methods when you call them.
I actually have a notification module that I inject which uses $mdDialog. Below is the code for it. Perhaps it will help.
(() => {
"use strict";
class notification {
constructor($mdToast, $mdDialog, $state) {
/* #ngInject */
this.toast = $mdToast
this.dialog = $mdDialog
this.state = $state
/* properties */
this.transitioning = false
this.working = false
}
openHelp() {
this.showAlert({
"title": "Help",
"textContent": `Help is on the way for ${this.state.current.name}!`,
"ok": "OK"
})
}
showAlert(options) {
if (angular.isString(options)) {
var text = angular.copy(options)
options = {}
options.textContent = text
options.title = " "
}
if (!options.ok) {
options.ok = "OK"
}
if (!options.clickOutsideToClose) {
options.clickOutsideToClose = true
}
if (!options.ariaLabel) {
options.ariaLabel = 'Alert'
}
if (!options.title) {
options.title = "Alert"
}
return this.dialog.show(this.dialog.alert(options))
}
showConfirm(options) {
if (angular.isString(options)) {
var text = angular.copy(options)
options = {}
options.textContent = text
options.title = " "
}
if (!options.ok) {
options.ok = "OK"
}
if (!options.cancel) {
options.cancel = "Cancel"
}
if (!options.clickOutsideToClose) {
options.clickOutsideToClose = false
}
if (!options.ariaLabel) {
options.ariaLabel = 'Confirm'
}
if (!options.title) {
options.title = "Confirm"
}
return this.dialog.show(this.dialog.confirm(options))
}
showToast(toastMessage, position) {
if (!position) { position = 'top' }
return this.toast.show(this.toast.simple()
.content(toastMessage)
.position(position)
.action('OK'))
}
showYesNo(options) {
options.ok = "Yes"
options.cancel = "No"
return this.showConfirm(options)
}
uc() {
return this.showAlert({
htmlContent: "<img src='img\\underconstruction.jpg'>",
ok: "OK",
title: "Under Construction"
})
}
}
notification.$inject = ['$mdToast', '$mdDialog', '$state']
angular.module('NOTIFICATION', []).factory("notification", notification)
})()
Then inject notification (lower case) into my controllers in order to utilize it. I store notification in a property of the controller and then call it with something like this:
this.notification.showYesNo({
clickOutsideToClose: true,
title: 'Delete Customer Setup?',
htmlContent: `Are you sure you want to Permanently Delete the Customer Setup for ${custLabel}?`,
ariaLabel: 'Delete Dialog'
}).then(() => { ...
this.notification.working = true
this.ezo.EDI_CUSTOMER.remove(this.currentId).then(() => {
this.primaryTab = 0
this.removeCustomerFromList(this.currentId)
this.currentId = 0
this.notification.working = false
}, error => {
this.notification.working = false
this.notification.showAlert({
title: "Error",
htmlContent: error
})
})
I'm trying to use $location.path() inside of an $interval to automatically navigate from tab to tab on a timer.
However, whenever I call $location.path(x) it only reloads my current view.
My code is as follows:
tabsController.js
(function () {
var injectParams = ['$location', '$routeParams', '$scope', '$rootScope', '$interval', 'teleAiDiagnosticsConfig'];
var TabsController = function ($location, $routeParams, $scope, $rootScope, $interval, teleAiDiagnosticsConfig) {
var vm = this;
$rootScope.autoNavInterval = {};
$rootScope.AutoNavActive = false;
$scope.tabs = [
{ link: '#!/vehicles', label: 'Vehicles', active: (($location.$$url.indexOf('/vehicle') !== -1) ? true : false) },
{ link: '#!/workzones', label: 'Workzones', active: (($location.$$url.indexOf('/workzone') !== -1) ? true : false) },
{ link: '#!/operatorStations', label: 'Operator Stations', active: (($location.$$url.indexOf('/operatorStation') !== -1) ? true : false) },
{ link: '#!/sessionStatus/123', label: 'Session Status (123)', active: (($location.$$url.indexOf('/sessionStatus') !== -1) ? true : false) }
];
// find the tab that should be marked as active
for (var i = 0; i < $scope.tabs.length; i++) {
if ($scope.tabs[i].active == true) {
$scope.selectedTab = $scope.tabs[i];
break;
}
}
if ($scope.selectedTab == undefined)
$scope.selectedTab = $scope.tabs[0];
$scope.setSelectedTab = function (tab) {
$scope.selectedTab = tab;
}
$scope.tabClass = function (tab) {
if ($scope.selectedTab == tab) {
return "active";
} else {
return "";
}
}
$scope.nextTab = function () {
for (var i = 0; i < $scope.tabs.length; i++) {
if ($scope.tabs[i] == $scope.selectedTab) {
if (i == $scope.tabs.length - 1) {
$location.path($scope.tabs[0].link);
if (!$scope.$$phase) $scope.$apply()
$scope.tabs[0].active = true;
$scope.selectedTab = $scope.tabs[0];
break;
}
else {
$location.path($scope.tabs[i + 1].link);
if (!$scope.$$phase) $scope.$apply()
$scope.tabs[i + 1].active = true;
$scope.selectedTab = $scope.tabs[i + 1];
break;
}
}
}
}
$scope.startAutoNav = function () {
$rootScope.AutoNavActive = true;
$rootScope.autoNavInterval = $interval(function () {
$scope.nextTab();
}, teleAiDiagnosticsConfig.autoNavTimer);
}
$scope.stopAutoNav = function () {
$rootScope.AutoNavActive = false;
$interval.cancel($rootScope.autoNavInterval);
}
$scope.startAutoNav();
};
TabsController.$inject = injectParams;
angular.module('teleAiDiagnostics').controller('TabsController', TabsController);
}());
Yes, yes, I know using $rootScope is not advised. I'm going to change it once I get $location.path() working.
I've tried it with and without the if (!$scope.$$phase) $scope.$apply() lines. I've also tried adding a call to $location.replace() but this doesn't do anything for me.
Whenever $location.path() is called the view section flashes but it just reloads the Vehicles view.
app.js
(function () {
var app = angular.module('teleAiDiagnostics', ['ngRoute', 'ngAnimate', 'ui.bootstrap']);
app.config(['$routeProvider', function ($routeProvider) {
var viewBase = 'app/views/';
$routeProvider
.when('/vehicles', {
controller: 'VehiclesController',
templateUrl: viewBase + 'vehicles.html',
controllerAs: 'vm'
})
.when('/vehicle/:id', {
controller: 'VehicleController',
templateUrl: viewBase + "vehicle.html",
controllerAs: 'vm'
})
.when('/workzones', {
controller: 'WorkzonesController',
templateUrl: viewBase + 'workzones.html',
controllerAs: 'vm'
})
.when('/workzone/:id', {
controller: 'WorkzoneController',
templateUrl: viewBase + "workzone.html",
controllerAs: 'vm'
})
.when('/operatorStations', {
controller: 'OperatorStationsController',
templateUrl: viewBase + 'operatorStations.html',
controllerAs: 'vm'
})
.when('/operatorStation/:id', {
controller: 'OperatorStationController',
templateUrl: viewBase + 'operatorStation.html',
controllerAs: 'vm'
})
.when('/sessionStatus/:id', {
controller: 'SessionStatusController',
templateUrl: viewBase + 'sessionStatus.html',
controllerAs: 'vm'
})
.otherwise({ redirectTo: '/vehicles' });
}]);
// Intialize slider
$('.flexslider').flexslider({
animation: 'slide',
slideshow: true,
pauseOnAction: true,
controlNav: true,
pauseOnHover: true,
touch: true,
directionalNav: false,
direction: 'horizontal',
slideshowSpeed: 6000,
smoothHeight: true
});
}());
Not sure why this isn't working. I've followed all the tips I could find and I'm still getting the same result. I'm tempted to just add UI-Router to my application and replace my routes with states.
Found it. The issue was related to the hash-bang (#!) in the URL.
I added a link to my tab definitions which does not contain the hash-bang and it works perfectly now.
tabsController.js
(function () {
var injectParams = ['$location', '$routeParams', '$scope', '$rootScope', '$interval', 'teleAiDiagnosticsConfig'];
var TabsController = function ($location, $routeParams, $scope, $rootScope, $interval, teleAiDiagnosticsConfig) {
var vm = this;
$rootScope.autoNavInterval = {};
$rootScope.AutoNavActive = false;
$scope.tabs = [
{ link: '#!/vehicles', refLink: '/vehicles', label: 'Vehicles', active: (($location.$$url.indexOf('/vehicle') !== -1) ? true : false) },
{ link: '#!/workzones', refLink: '/workzones', label: 'Workzones', active: (($location.$$url.indexOf('/workzone') !== -1) ? true : false) },
{ link: '#!/operatorStations', refLink: '/operatorStations', label: 'Operator Stations', active: (($location.$$url.indexOf('/operatorStation') !== -1) ? true : false) },
{ link: '#!/sessionStatus/123', refLink: '/sessionStatus/123', label: 'Session Status (123)', active: (($location.$$url.indexOf('/sessionStatus') !== -1) ? true : false) }
];
// find the tab that should be marked as active
for (var i = 0; i < $scope.tabs.length; i++) {
if ($scope.tabs[i].active == true) {
$scope.selectedTab = $scope.tabs[i];
break;
}
}
if ($scope.selectedTab == undefined)
$scope.selectedTab = $scope.tabs[0];
$scope.setSelectedTab = function (tab) {
$scope.selectedTab = tab;
}
$scope.tabClass = function (tab) {
if ($scope.selectedTab == tab) {
return "active";
} else {
return "";
}
}
$scope.nextTab = function () {
for (var i = 0; i < $scope.tabs.length; i++) {
if ($scope.tabs[i] == $scope.selectedTab) {
if (i == $scope.tabs.length - 1) {
$location.path($scope.tabs[0].refLink);
$location.replace();
if (!$scope.$$phase) $scope.$apply()
$scope.tabs[0].active = true;
$scope.selectedTab = $scope.tabs[0];
break;
}
else {
$location.path($scope.tabs[i + 1].refLink);
$location.replace();
if (!$scope.$$phase) $scope.$apply()
$scope.tabs[i + 1].active = true;
$scope.selectedTab = $scope.tabs[i + 1];
break;
}
}
}
}
$scope.startAutoNav = function () {
$rootScope.AutoNavActive = true;
$rootScope.autoNavInterval = $interval(function () {
$scope.nextTab();
}, teleAiDiagnosticsConfig.autoNavTimer);
}
$scope.stopAutoNav = function () {
$rootScope.AutoNavActive = false;
$interval.cancel($rootScope.autoNavInterval);
}
$scope.startAutoNav();
};
TabsController.$inject = injectParams;
angular.module('teleAiDiagnostics').controller('TabsController', TabsController);
}());
Hope this helps someone.
I have a property in my factory and a sync() method to update it, but when accessing from controller the value never changes.
My router: (Initialise events with resolve)
'use strict';
myApp
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('app', {
abstract: true,
views: {
'header': {
controller: 'HeaderCtrl',
templateUrl: 'views/header/_header.html'
},
'footer': {
templateUrl: 'views/footer/_footer.html'
}
}
})
.state('app.events', {
url: '^/',
views: {
'content#': {
controller: 'EventsCtrl',
templateUrl: 'views/events/_events.html',
resolve: {
postPromise: ['EventsServ', function(EventsServ) {
return EventsServ.getAll();
}]
}
}
}
})
.state('app.about', {
url: '^/sobre',
views: {
'content#': {
templateUrl: 'views/about/_about.html'
}
}
})
.state('app.contact', {
url: '^/contato',
views: {
'content#': {
controller: 'ContactCtrl',
templateUrl: 'views/contact/_contact.html'
}
}
});
}]);
My controller: (Now sync with facebook and update events)
'use strict';
myApp
.controller('EventsCtrl', ['$scope', 'EventsServ', '$filter', '$window', 'Facebook', 'postPromise', '$log', '$timeout', function($scope, EventsServ, $filter, $window, Facebook, postPromise, $log, $timeout) {
$scope.alerts = [];
$scope.events = EventsServ.all(); // <<<< Never update, keep the same value obtained in router.
$scope.periods = [{
label: 'HOJE',
labelColor: 'success',
startTime: $filter('clearTime')(new Date()),
endTime: $filter('clearTime')(new Date()),
events: []
}, {
label: 'PRÓXIMOS DIAS',
labelColor: 'primary',
startTime: $filter('clearTime')($filter('addDay')(new Date(), 1)),
endTime: $filter('clearTime')($filter('addDay')(new Date(), 8)),
events: []
}, {
label: 'PRÓXIMAS SEMANAS',
labelColor: 'warning',
startTime: $filter('clearTime')($filter('addDay')(new Date(), 9)),
events: []
}];
if (postPromise.status >= 200 && postPromise.status < 300) {
angular.forEach($scope.events, (function(event) {
var eventDate = $filter('clearTime')(event.start_time);
angular.forEach($scope.periods, (function(period) {
if (eventDate >= period.startTime && (eventDate <= period.endTime || !period.endTime)) {
period.events.push(event);
}
}));
}));
Facebook.getLoginStatus(function(response) {
if(response.status === 'connected') {
EventsServ.sync();
$log.info($scope.events);
} else {
$log.info('notLoggedIn');
}
});
} else {
$scope.alerts.push({
type: 'danger',
msg: 'Ooops! Não foi possível buscar os eventos.'
});
}
$scope.openEvent = function(event) {
$window.open('http://facebook.com/events/' + event.id, '_blank');
};
$scope.closeAlert = function(index) {
$scope.alerts.splice(index, 1);
};
}])
.filter('addDay', function() {
return function(date, days) {
return new Date(date.setDate(date.getDate() + days));
};
})
.filter('clearTime', function() {
return function(date) {
var d = new Date(date);
d.setHours(0,0,0,0);
return d;
};
});
I build my view looping through $scope.events.
My factory:
'use strict';
myApp
.factory('EventsServ', ['$http', '$q', 'Facebook', 'PagesServ', '$log', function($http, $q, Facebook, PagesServ, $log) {
var factory = {
events: []
};
factory.all = function() {
return factory.events;
};
factory.getAll = function() {
return $http.get('/events.json')
.success(function(response) {
angular.copy(response, factory.events);
})
.error(function(response) {
$log.error('Failed to get events.');
});
};
factory.sync = function() {
PagesServ.getAll().then(function(response) {
var pages = PagesServ.pages;
var events = [];
var pagesPromises = [];
var eventsPromises = [];
angular.forEach(pages, function(page, key) {
pagesPromises.push(Facebook.api(page.facebook_id, function(response) {
page.facebook_id = response.id;
page.name = response.name;
page.image = 'image.jpg';
delete page.events;
delete page.created_at;
delete page.updated_at;
}));
eventsPromises.push(Facebook.api(page.facebook_id + '/events', function(response) {
var pageEvents = response.data;
angular.forEach(pageEvents, function(event, key) {
event.page = page;
});
events = events.concat(pageEvents);
}));
});
$q.all(pagesPromises).then(function() {
$log.info(pages);
}, function(reason) {
$log.error('Failed to syncs pages: ' + reason);
});
$q.all(eventsPromises).then(function() {
factory.events = [];
angular.forEach(events, function(event, key) {
var eventSynced = {
facebook_id: event.id,
image: '',
name: event.name,
description: event.description,
start_time: event.start_time,
end_time: event.end_time,
going: 397,
address: '...',
page: event.page
}
factory.events.push(eventSynced);
});
$log.info(factory.events); // <<<<< Here the new value is correct!
}, function(reason) {
$log.error('Failed to syncs events: ' + reason);
});
});
};
return factory;
}]);
The new value of the property inside factory is correct when printing to console, but in controller the value never changes, is always [ ].
When have data I want to stay in sync between a controller and a factory, or a factory and multiple controllers, I set the data item I want to access in my controller to the object or array in the factory:
// in your controller change this
$scope.events = EventsServ.all();
// to use the object
$scope.events = EventsServ.events;
In your sync function where you are iterating over the events, push each one into a temporary array, then use angular.copy to make the update to the array available to the controller.
// at the line right before you log the events in the factory use
angular.copy(tempArray, factory.events);
$log.info(factory.events);
More info: http://www.justinobney.com/keeping-angular-service-list-data-in-sync-among-multiple-controllers/
.controller('CyclesController', function ($scope, $state) {
$scope.age = 0;
$scope.name = "";
$scope.email = "";
$scope.calculateByAge = function (age, name, email) {
$scope.data = $scope.data || {};
if (age > 0) {
$scope.data.age = age;
$scope.data.name = name;
$scope.data.email = email;
$state.go('tab.cycles-detail');
}
}
})
.controller('CyclesDetailController', function ($scope, $stateParams, CyclesService) {
console.log('scope data', $scope.data); // <--- undefined.
})
This may be a dumb question, but can get to get the data from the form on the CyclesDetailController controller.
If it's simple property you could do it by routing. Just change your "tab.cycles-detai' to 'tab.cycles-detai/:age' in your ui-router configuration and pass it when you're redirecting: $state.go('tab.cycles-detail', {age: age});
in 'CyclesDetailController' access it by $stateParams.age;
e.g:
//app.config
//...
.state('tab.cycles-detail', {
url: "^detail/{age:int}",
controller: 'CyclesDetailController',
templateUrl: "url_for_detail_template"
})
//...
// CyclesController
.controller('CyclesController', function ($scope, $state) {
$scope.age = 0;
$scope.calculateByAge = function (age) {
$scope.data = $scope.data || {};
if (age > 0) {
$scope.data.age = age;
$state.go('tab.cycles-detail', {age: age);
}
}
})
//CyclesDetailController
.controller('CyclesDetailController', function ($scope, $stateParams, CyclesService) {
console.log('scope data', $stateParams.age);
})
//
If you want to pass data from one route to another but dont want to expose it in browser menu bar, you can use squash.
Example -
.state('app.enroll', {
url: '/enroll/',
params: {
classId: {
value: null,
squash: true
},
className: {
value: null,
squash: true
}
},
title: 'Students Enrollment',
templateUrl: helper.basepath('enroll.html')
})
2nd Technique -
You can use localStorage / cookies to save data and retrieve at later stage.
3rd Technique -
You can always share data via services/factory in between controllers.