I'm developing application using Ionic Framework and there's problem I can't solve.
I have few views that are steps and must share data, user can also step back, go to some else views and come back later. His input should be stored until last step is finished then I can persist model and I need new empty one.
I used factory for this, but I can't find a way to clear object that is returned. Is it possible?
What's some other approaches that I can use here?
app.js
.state('topup', {
url: "/topup",
abstract: true,
templateUrl: "templates/topup/topup.html",
controller:'TopupCtrl'
})
.state('topup-1', {
url: "/topup-1",
templateUrl: "templates/topup/topup-1.html",
controller:'TopupCtrl'
})
.state('topup-2', {
url: "/topup-2",
templateUrl: "templates/topup/topup-2.html",
controller:'TopupCtrl'
})
controllers.js
.controller('TopupCtrl', function($scope, $state, TopupData, HistoryData) {
$scope.data = TopupData.getCurrent();
$scope.selectOperator = function(operator) {
$scope.data.Operator = operator;
$state.go("topup-2");
};
$scope.acceptTopup = function(){
HistoryData.getHistory().push($scope.data);
console.log(HistoryData.getHistory());
TopupData.setCurrent({});
$state.go("main");
};
})
services.js
.factory('TopupData', function () {
var service = {};
var Model = {};
service.setCurrent = function(value)
{
Model = value;
};
service.getCurrent = function(value)
{
return Model;
};
return service;
})
Try this way.
console.log(HistoryData.getHistory());
var resetObj = {};
TopupData.setCurrent(resetObj);
$state.go("main");
I'd suggest you to don't define a controller on state level, if they are of the same name, re initializing same controller on state change is not good idea.
HTML
<div ng-controller="TopupCtrl">
<ui-view></ui-view>
</div>
CODE
.state('topup', {
url: "/topup",
abstract: true,
templateUrl: "templates/topup/topup.html"
})
.state('topup-1', {
url: "/topup-1",
templateUrl: "templates/topup/topup-1.html"
})
.state('topup-2', {
url: "/topup-2",
templateUrl: "templates/topup/topup-2.html"
})
Then i don't think so you will need factory anymore, as there no need to share a scope.
Changing code like this, solved my problem:
var resetObj = {};
TopupData.setCurrent(resetObj);
$state.go("main").then(function(){
$ionicHistory.clearHistory();
$ionicHistory.clearCache();
});
Related
I have a controller in AngluarJS defined like so:
'use strict';
var app = angular.module('app');
app.controller('AppCtrl', ['sth',
function (sth) {
this.inverse = false;
}
]);
here is routes deffinition:
$stateProvider.
state('app', {
abstract: true,
templateUrl: 'app/views/layout.html',
controller: 'AppCtrl',
controllerAs: 'app',
resolve: {}
}).
state('app.settings', {
abstract: true,
url: '/settings',
template: '<ui-view/>',
onEnter: function () {
}
});
How to access inverse variable from AppCtrl in app.settings route?
If you want to share data between 2 controllers, a service/factory is your best bet. Below is a an example of how you would do it. I have written it free-hand, so there may be syntax errors, but you get the idea.
app.controller('AppCtrl', ['sth', 'SharedData',
function (sth, SharedData) {
SharedData.inverse = false;
}
]);
app.factory('SharedDate', function() {
var data = {
inverse: true // or whatever default value you want to set
};
return data;
})
Now, you can inject SharedData factory in any controller, where you want to use that data.
app.js:
$stateProvider.state('datasource', {
url: '/datasource',
templateUrl: 'views/datasource.html',
controller: 'datasourceController'
});
$stateProvider.state('datasourceList', {
url: '/datasource/:datasourceId',
templateUrl: 'views/datasource.list.html',
controller: 'datasourceController'
});
Then, I've a function activated onClick defined in (datasourceController)
$scope.submitSelected = function() {
if (angular.isDefined($scope.selectedSource)) {
$scope.datasource = dataSourcesService.find($scope.selectedSource.id);
$state.go('datasourceList', {datasourceId : datasource});
}
}
As I said, in my datasource.html view have an element click that triggers submitSelected() function
I can retrieve data successfully from my service based on ID when call it in function.
Problem is, i cant access the results (scope) of it in the view datasource.list.html after changing the state.
Add 'param' in state config
$stateProvider.state('datasource', {
url: '/datasource',
templateUrl: 'views/datasource.html',
controller: 'datasourceController'
});
$stateProvider.state('datasourceList', {
url: '/datasource/:datasourceId',
templateUrl: 'views/datasource.list.html',
params: ['index', 'anotherKey'],
controller: 'datasourceController'
});
And get values using $stateParams in another controller
app.controller('datasourceController', function($scope, $stateParams) {
var index = $stateParams.index;
var anotherKey = $stateParams.anotherKey;
});
'use strict'
var hsbc = angular.module('hsbc',['ngResource','ngRoute']);
hsbc.config(['$routeProvider','$locationProvider', function ($routeProvider, $locationProvider){
//console.log('config part working');
$routeProvider
.when('/login', {
controller: 'hsbccontroller',
templateUrl: 'modules/authentication/views/login.html',
hideMenus: true
})
.when('/gloabltranfer', {
controller: 'hsbccontroller',
templateUrl: 'modules/home/views/gloabltranfer.html'
})
.when('/tranferReq', {
controller: 'hsbccontroller',
templateUrl: 'modules/home/views/TransferRquest.html'
})
.when('/reviewdetail', {
controller: 'hsbccontroller',
templateUrl: 'modules/home/views/Reviewdetails.html'
})
.when('/confirmdetail', {
controller: 'hsbccontroller',
templateUrl: 'modules/home/views/confirmdetails.html'
})
.when('/', {
templateUrl: 'modules/authentication/views/login.html'
})
.otherwise({ redirectTo: '/login' });
}]).controller('hsbccontroller', ['$scope','$http','$resource','$location', function($scope,$http,$resource,$location, transfer){
var gformcountry, gtocountry, userID, formData;
$scope.hsbcaccts = [];
$scope.countries = [];
$scope.login = function(){
var username = $scope.username;
var pass = $scope.password;
if(username =='test' && pass =='test'){
username = 1234;
$location.path('/gloabltranfer');
}
else if(username =='test2' && pass =='test2'){
username = 2222;
$location.path('/gloabltranfer');
}
else{
$location.path('/login');
}
}
$http.get('http://localhost/api/Accounts').success(function(data) {
$scope.hsbcaccts = data.body;
}).error(function(){
alert('Sorry server down at moment. please some time later');
});
$http.get('http://localhost/api/Country').success(function(data) {
$scope.countries = data.body;
}).error(function(){
alert('Sorry server down at moment. please some time later');
});
/*$http.get('json/currency.json').success(function(data) {
$scope.countries = data;
});*/
$scope.countryFromTo = function(){
$scope.fromData ={ 'fromcountry':$scope.fromcountry,'tocountry':$scope.tocountry};
$location.path('/tranferReq');
}
$scope.tranferForm = function(){
$scope.tranferForm ={ 'fromaccount':$scope.fromaccount,'toaccount':$scope.toaccount, };
return $scope.tranferForm;
$location.path('/reviewdetail');
}
$scope.reviewdetails = function(){
//alert($scope.tranferForm);
$location.path('/confirmdetail');
}
$http.get('http://localhost/api/Accounts').success(function(data){
//alert(data.id);
$scope.hsbcaccts = data;
});
}]);
Here getting data from ng-click tranferForm function without submitting data try binding to next page $scope tranferForm function collecting data and display in the page reviewdetail page.
and then my controller twice at a time.
First thing first, using same controllers in different pages means two different instances, completely independent of each other.
Now to share the variables between controllers,there are two ways to do this:
Store data in factories and fetch from the factories in other page.
But a parent controller at body level, or above the view node, and store the values in $scope variables of parent controller. Usually this is on the same html element as the ng-app and is supposed to be the parent of all the controllers.
Plus I think you should be using different controllers.
Putting same controller defeats the purpose of modular programming.
I don't know your case but if possible, create different controllers with different names and put only functions used per page in those controllers.
If there are some functions which are needed in all the places,create a generic function and put it in a service.
i am just learning basics of angular and today it started to change my app using a factory to get data and implementing route provider ! So far everything works fine! But when I try to add data on another view and head back to my list view scope is reloaded again from factory and no added data shows up.
My approach won't work because each time change my view I will call my controller which reloads data from factory! What can I do to make my Add template will work and changes data everywhere else too.
Maybe somebody can give me a tip how to cope with this problem ?
script.js
var app = angular.module('printTrips', ['ngRoute']);
app.factory('tripFactory', function($http) {
return{
getTrips : function() {
return $http({
url: 'trips.json',
method: 'GET'
})
}
}
});
app.controller('TripController', function($scope, $filter, tripFactory) {
$scope.trips = [];
tripFactory.getTrips().success(function(data){
$scope.trips=data;
var orderBy = $filter('orderBy');
$scope.order = function(predicate, reverse) {
$scope.trips = orderBy($scope.trips, predicate, reverse)};
$scope.addTrip = function(){
$scope.trips.push({'Startdate':$scope.newdate, DAYS: [{"DATE":$scope.newdate,"IATA":$scope.newiata,"DUTY":$scope.newduty}]})
$scope.order('Startdate',false)
$scope.newdate = ''
$scope.newiata = ''
$scope.newduty = ''
}
$scope.deleteTrip = function(index){
$scope.trips.splice(index, 1);
}
});
});
view.js
app.config(function ($routeProvider){
$routeProvider
.when('/',
{
controller: 'TripController',
templateUrl: 'view1.html'
})
.when('/view1',
{
controller: 'TripController',
templateUrl: 'view1.html'
})
.when('/view2',
{
controller: 'TripController',
templateUrl: 'view2.html'
})
.when('/addtrip',
{
controller: 'TripController',
templateUrl: 'add_trip.html'
})
.otherwise({ redirectTo: 'View1.html'});
});
Here is my plunker
Thanks for your help
You should use Service instead of Factory.
Services are loaded each time they are called. Factory are just loaded once.
app.service('tripFactory', function($http) {
return{
getTrips : function() {
return $http({
url: 'trips.json',
method: 'GET'
})
}
}
});
My question is two fold:
1 - I have a parent state and several child states using ui.router, there's one object (stored in mongodb) that is need in all states, but it gets updated by all states. In this scenario does it make sense to use the parent state's resolve option to populate the object?
2 - If this is the proper way to do this, how can I update that "reference" (the mock service injector created by the ui.router) to that object from every state.
To help in explain he's a example of the idea (lot's of code ommited)
.state('parent',resolve:{objectX:return x.promise;},...);
.controller('childstateCtrl',$scope,objectX){
$scope.data.objectX = objectX;
$scope.someEvent =function(){
// something updates objectX on the scope
}
}
.controller('otherChildCtrl',$scope,objectX){
// how to get the updated objectX?
}
Thanks in advance
Not fully sure if I can see where is the issue... but if you are searching for a way how to share access to updated reference, it should be easy. There is an example
Let's have these states
$stateProvider
.state('root', {
abstract: true,
template: '<div ui-view></div>',
resolve: {objectX : function() { return {x : 'x', y : 'y'};}},
controller: 'rootController',
})
.state('home', {
parent: "root",
url: '/home',
templateUrl: 'tpl.example.html',
})
.state('search', {
parent: "root",
url: '/search',
templateUrl: 'tpl.example.html',
})
.state('index', {
parent: "root",
url: '/index',
templateUrl: 'tpl.example.html',
})
Working with only one controller (for a root state):
.controller('rootController', function($scope, objectX){
$scope.data = { objectX: objectX };
})
And for this example, this is shared template:
<div>
<h3>{{state.current.name}}</3>
x <input ng-model="data.objectX.x"/>
y <input ng-model="data.objectX.y"/>
</div>
So, in this scenario, parent (root) has injected an object data into $scope. That reference is then inherit as described here:
Scope Inheritance by View Hierarchy Only
Check that example in action here. If you need more details (than in the link above, check this Q&A)
you could store it in a service.
.service("myService", function($q) {
// the actual data is stored in a closure variable
var data = undefined;
return {
getPromise: function() { // promise for some data
if (data === undefined) // nothing set yet, go fetch it
return $http.get('resourceurl').then(function(value) { data = value; return data; });
else
return $q.when(data); // already set, just wrap in a promise.
},
getData: function() { return data; }, // get current data (not wrapped)
setData: function(newDataVal) { data = newDataVal; } // reset current data
}
})
// `parent` wont' enter until getPromise() is resolved.
.state('parent', resolve:{objectX: function(myService) { return myService.getPromise(); } });
.controller('childstateCtrl', $scope, myService) {
$scope.data.objectX = myService.getData();
$scope.someEvent = function(someData){
myService.setData(someData);
}
}
.controller('otherChildCtrl', $scope, myService){
// how to get the updated objectX?
var data = myService.getData();
}