I am trying to create a form that works as follows:
Main View has list of all the fields
e.g 1. Merchant, 2. Amount 3. Date
The form is fairly long. Instead of doing a multistep form, I am hoping to do the following:
Tap on the Merchant to open a select merchant view and select merchant to return the value to main view.
Tap on Amount to enter amount view. Once the value is entered return the value to main view
Tap on date to enter the date view. Once the date is selected return int to the main view.
Any tips?
You can use a service to share data between the controllers associated with each view.
app.service('YourService', function($q) {
return {
details:
{
name: 'Merchant_1', //Some default values
amount: 100,
date: ""
}
,
getDetails: function() {
return this.details
},
setDetails: function(name,amount,date) {
this.details.name = name;
this.details.amount = amount;
this.details.date = date;
},
setName: function(name){
this.details.name = name;
}
}
});
and in your controllers inject 'YourService'. For eg. the controller for the merchant view.
app.controller( 'MerchantViewCtrl', function( $scope, YourService ) {
var onSelect = function(MerchantName){
YourService.setName(MerchantName);
}
});
Select Merchant view
<select ng-click="onSelect(merchant.name)" ng-options="merchant in merchantsList">
</select>
and in your main view controller
app.controller( 'MainViewCtrl', function( $scope, YourService ) {
var details = YourService.getDetails();
$scope.name = details.name;
$scope.amount = details.amount;
$scope.date = details.date;
});
Related
User from front page ,select the city from below list and as per search product are displayed.
But after the every product displayed , page reload and City selected get changed to First city and user need to select again city for every search.
Need help how to overcome this issue and set the city to user selected ,not refreshed every time .
//Define an angular module for our app
var app = angular.module('myApp', ['ui.bootstrap']);
app.controller('autocompleteController', function($scope, $http) {
$scope.cities = [
{name: 'London'},
{name: 'Paris'},
{name: 'Newyork'},
];
$scope.selectedCities = $scope.cities[0];
var initalizeproduct = function() {
$scope.products = $http.get("/getproduct/"+$scope.selectedCities.name).success(function(data){
$scope.products = data.products;
});
}
initalizeproduct($scope.products);
$scope.changeCity = function() {
initalizeproduct();
}
$scope.onSelectPart = function (item) {
$scope.selectedproducts = item;
window.location.href = "/product/"+$scope.selectedproducts.fields.slug;
};
});
From HTML Page :
<select ng-model="selectedCities" ng-change="changeCity()" ng-options="cities.name for cities in cities" style="background :transparent; border:0px; outline: none;">
</select>
Replace window.location.href = "..."; with:
$http
.get("/product/"+$scope.selectedproducts.fields.slug)
.then(function( ̶d̶a̶t̶a̶ response) {
var data = response.data;
// Get the HTML part from 'data' that you would like to display and add it to DOM
});
to begin with.
I have two views(2 html templates) both have one common controller
now in view 1 which contains ng-repeat items
for example :
In "view 1" : ng-repeat = "monthid in years"
it shows:
month 1,
month 2,
...
month 12
So now i want to click on "month 1" and send its value suppose its name like "january" to "view 2"
In view 2, there will be only one thing just month 1's name(january).
Like this,
If i click on "month 2" there will be only one thing just month 2's name (February) in view 2.
How to achieve this?
I can see three solutions to share data between controllers:
Store your variable in a service and inject your service in both controller.
Use events (i.e $broadcast, $on methods) to notify controllers.
Use scope inheritance and store your variable in a parent controller. This should be avoided most of the time since refactoring and unit tests may be hard.
In my opinion, the best way to share variables between two controllers is to use a service (simple, easy to test):
Store the month in your service.
Inject the service in both controller.
Here is an example:
angular.module('app', [])
.service('filterService', function() {
var _year;
this.getYear = function() {
return _year;
};
this.setYear = function(year) {
_year = year;
};
})
.controller('Ctrl1', function($scope, filterService) {
$scope.chooseYear = function(year) {
filterService.setYear(year);
};
})
.controller('Ctrl2', function($scope, filterService) {
$scope.year = filterService.getYear();
$scope.$watch(filterService.getYear, function(newValue) {
$scope.year = newValue;
});
});
Note that if you can use Object.defineProperty method (available with IE >= 9), your controllers can be refactored to use $scope.year everywhere (and you can remove the call to the $watch mhttps://plnkr.co/edit/G2pVFMV5Z2yXYSCkgZYs?p=infoethod):
angular.module('app', [])
.service('filterService', function() {
var _year;
this.getYear = function() {
return _year;
};
this.setYear = function(year) {
_year = year;
};
})
.controller('Ctrl1', function($scope, filterService) {
Object.defineProperty($scope, 'year', {
get: filterService.getYear,
set: filterService.setYear
});
})
.controller('Ctrl2', function($scope, filterService) {
Object.defineProperty($scope, 'year', {
get: filterService.getYear,
set: filterService.setYear
});
});
Here is a plunkr if you want to test : https://plnkr.co/edit/G2pVFMV5Z2yXYSCkgZYs?p=info
I need a bit of a code review, i'm having trouble getting my ng-change function to trigger and update the value in both controllers, i've created a factory service and have injected it into both controllers but on the second AppCtrl console.log() value prints only once during initialization, and would like to have the ng-change value also update on the second controller and not only on the first.
This is what i have so far:
<ion-radio ng-repeat="rate in rates"
ng-value="rate.id"
ng-change="rateTypeChanged(rate)"
ng-checked="rate.selected"
ng-model="currentRate.selectedRate">
{{ rate.title }}
</ion-radio>
controller for sidebar:
.controller('SidebarCtrl', function($scope, typesOfRates) {
$scope.rates = typesOfRates.rateType;
$scope.currentRate = {
selectedRate: 'hourly'
};
$scope.rateTypeChanged = function(rate) {
console.log("Selected goalType, text:", rate.title, "value:", rate.id);
typesOfRates.setRate(rate.id);
}
In controller 2:
.controller('AppCtrl', function($scope, typesOfRates, $state, $rootScope) {
console.log( typesOfRates.getRate() );
//runs only once, but not again when ng-change event is triggered
my service:
.factory('typesOfRates', function typesOfRates($rootScope) {
var typesOfRates = {};
typesOfRates.myRates = [];
typesOfRates.rateType = [
{ title: "Hourly", id: "hourly", selected: true },
{ title: "Daily", id: "daily", selected: false },
{ title: "Monthly", id: "monthly", selected: false }
];
typesOfRates.currentRate = "hourly";
var setRate = function(currentRate) {
if (typesOfRates.myRates.length > 0) typesOfRates.myRates = [];
typesOfRates.myRates.push(currentRate);
}
var getRate = function() {
return typesOfRates.myRates;
}
return {
rateType: typesOfRates.rateType,
getRate: getRate,
setRate: setRate
}
});
The way you are doing to achieve the objective seems bit out of the box. The second controller will be initialized only once. If you want to access the undated value in the second controller you need to following one of the following approaches.
1) Watch for changes in typesOfRates.myRates in the second controller.
$watch is used to track changes for a model variable in the scope. The
$watch requires $scope, as we have 2 different controllers, the scopes will be different (I feel so unless you have bound the two controllers
in the same html). So it won't be the correct to use $watch in this
situation.
2) Use a broad cast receiver concept
Advantage : It's preferred as there is no continuous watching required, and triggered only when the value changes
Step 1) In the first controller, register a broadcast as:
.controller('SidebarCtrl', function($scope, typesOfRates) {
$scope.rates = typesOfRates.rateType;
$scope.currentRate = {
selectedRate: 'hourly'
};
$scope.rateTypeChanged = function(rate) {
console.log("Selected goalType, text:", rate.title, "value:", rate.id);
typesOfRates.setRate(rate.id);
//$broadcast(name, args); here name you have to give in a file
//which is commonly accessible like constants.js, just create a
//file and include in you index.html, pass your rates as args
$rootScope.$broadcast(constants_config.TYPE_RATES_CHANGED, rate.id);
}
});
Step 2) Create constants.js file and include in your index.html as:
<!-----Constants Classes---->
<script src="Constants.js"></script>
In constants.js add the following code:
var constants_config = {
TYPE_RATES_CHANGED : "TYPE_RATES_CHANGED",
}
Step 3) Register your listener in the second controller as
.controller('AppCtrl', function($scope, typesOfRates, $state, $rootScope) {
// #CallBack
// Description : Callback function for user details fetched
$scope.$on(constants_config.TYPE_RATES_CHANGED, function(args) {
//Assign the value to a global variable or a scope variable so
//that you can access it throughout your controller
$scope.Rates = typesOfRates.getRate();
//Now the console will work
console.log( typesOfRates.getRate() );
});
});
Further Reference:
- Broadcasts : $broadcast
- Listeners : $on
- Watch : $watch
I have an AngularJS service which should get a JSON object and create three arrays based on differing criteria (all, searchable and has coordinates). These arrays need to be referenced by more than one controller, hence the use of a service.
When I test any of the three arrays the array within the service itself (as below), all three are correctly populated.
However, all three of my arrays are empty when referenced by any controller.
What am I missing here?
app.service('$stationsList', ['$http', function($http){
var stationsList = [],
searchableStations = [],
locatableStations = [];
$http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
stationsList = res.data; // Set all stations to 'stationsList'
if(elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable (has a full link)
searchableStations.push(elm); // It does - add the station to 'searchableStations'
if( // Check to see if the station can be checked as the closest station (has coordinates)
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
)
locatableStations.push(elm); // It does - add the station to 'locatableStations'
});
console.log(stationsList);
console.log(searchableStations);
console.log(locatableStations);
});
return{
getList: function(){
return stationsList;
},
setList: function(value){
stationsList = value;
},
getSearchable: function(){
return searchableStations;
},
setSearchable: function(value){
searchableStations = value;
},
getLocatable: function(){
return locatableStations;
},
setLocatable: function(value){
locatableStations = value;
}
};
}]);
Example of how I'm referencing service -
app.controller('searchCtrl', ['$scope', '$http', '$localStorage', '$stationsList', function($scope, $http, $localStorage, $stationsList){
$scope.stationsList = $stationsList.getSearchable(); // Grab a list of all stations
$scope.selectStation = click_selectStation; // Handle clicks of a station within the 'searchCtrl' controller
$scope.localStorage = $localStorage.$default({ // Grab the local storage (so that it can be updated when the user selects a station)
recentStations: [] // Set a default value of '[]' for recentStations in case it doesn't exist
});
}]);
Edit
Derived from the answer posted by PankajParkar below, here is the service that will return the three arrays that I require.
However, my issue here is that every call to a method within the service triggers another async call to $http.get my JSON data. This is exactly what I was trying to avoid by using a service.
My desired outcome is one JSON call per page load, with my 3 arrays being created from that JSON call and then accessible to my controllers as and when required. If a service is not the correct answer, I am certainly open to other suggestions.
app.service('$stationsList', ['$http', function($http){
var searchableStations = [],
locatableStations = [];
/**
* Grab all stations (for the master list)
*/
var getAllStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
return res.data;
});
};
/**
* Grab only searchable stations (those with full links)
*/
var getSearchableStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
if (elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable
searchableStations.push(elm); // It is - add the station to 'searchableStations'
});
return searchableStations;
});
};
/**
* Grab only locatable stations (those with coordinates)
*/
var getLocatableStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
if(
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
) // Check to see if the station is locatable
locatableStations.push(elm); // It is - add the station to 'locatableStations'
});
return locatableStations;
});
};
return{
getAll: getAllStations,
getSearchable: getSearchableStations,
getLocatable: getLocatableStations
};
}]);
Your current code is failing because you made asynchronous ajax call & accepting value as soon as it made. That's why you are getting your values as undefined.
You need to wait till your ajax gets completed, that could be implemented using returning ajax promise to controller from service. So i'd suggest you to create a new method which will do $http ajax and will return promise from that function & that will execute .then function of controller that called the getSearchableStations. Below snippet will give you an Idea what I wanted to say.
Service
app.service('$stationsList', ['$http', function($http) {
var stationsList = [],
searchableStations = [],
locatableStations = [];
var getSearchableStations = function() {
return $http.get('stations.json').then(function(res) { // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm) { // Map all stations...
stationsList = res.data; // Set all stations to 'stationsList'
if (elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable (has a full link)
searchableStations.push(elm); // It does - add the station to 'searchableStations'
if ( // Check to see if the station can be checked as the closest station (has coordinates)
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
)
locatableStations.push(elm); // It does - add the station to 'locatableStations'
});
console.log(stationsList);
console.log(searchableStations);
console.log(locatableStations);
return locatableStations; //return data from here.
});
};
return {
getList: function() {
return stationsList;
},
setList: function(value) {
stationsList = value;
},
getSearchable: function() {
return searchableStations;
},
setSearchable: function(value) {
searchableStations = value;
},
getLocatable: function() {
return locatableStations;
},
setLocatable: function(value) {
locatableStations = value;
},
//added new function
getSearchableStations: getSearchableStations
};
}]);
Inside you controller you will call service getSearchableStations method that does return promise, You will use .then function that would get called when promise get resolved. Same has been shown below with code.
Controller
app.controller('searchCtrl', ['$scope', '$http', '$localStorage', '$stationsList',
function($scope, $http, $localStorage, $stationsList){
$stationsList.getSearchableStations().then(function(data){
$scope.stationsList = data;
$scope.selectStation = click_selectStation; // Handle clicks of a station within the 'searchCtrl' controller
$scope.localStorage = $localStorage.$default({ // Grab the local storage (so that it can be updated when the user selects a station)
recentStations: [] // Set a default value of '[]' for recentStations in case it doesn't exist
});
}); // Grab a list of all stations
}]);
I have very simple question about getting data from WebSql
I have DropDown i.e
<select id="selectCatagoryFood" data-role="listview" data-native-menu="true"
ng-init="foodCatagory = foodCatagories.cast[0]"
ng-options="foodCatagory as foodCatagory.text for foodCatagory in foodCatagories.cast"
ng-model="foodCatagory"
ng-change="changeFoodCatagory()">
</select>
now i want to add data init from webSQL. I already get Data from webSql but i am confuse that how to add that data into DropDown
An example or hints maybe very helpful for me.
Update 1 :: Add Controller Code
myApp.controller('foodSelection',function($scope,foodCatagories){
$scope.foodCatagories = foodCatagories;
$scope.changeFoodCatagory = function(){
alert($scope.foodCatagory.value);
}
});
Update 2 webSQL and JayData
_context.onReady({
success: showData,
error: function (error){
console.log(error);
}
});
function showData(){
var option = '';
_context.FoodGroup.forEach(function(FG)
{
option += '<option value="'+FG.FoodGroupID+'">'+FG.Description+'</option>';
}).then(function(){
console.log(option);
});
}
Update 3
var myApp = angular.module('myApp',[]);
myApp.factory('foodCatagories',function(){
var foodCatagories = {};
foodCatagories.cast = [
{
value: "000",
text: "Select Any"
}
];
return foodCatagories;
});
Update 4
One thing that i didn't mention is that I am using JayData for getting data from webSQL to my App
I will try to explain how it works:
EDIT: Live demo
html
Here is your stripped down select.
<select ng-options="item as item.text for item in foodCategories"
ng-model="foodCategory"
ng-required="true"
ng-change="changeFoodCategory()">
</select>
The directive ng-options will fill automatically the option elements in your select. It will take the foodCategories variable from the $scope of your controller and foreach item in the collection, it will use the text property as the label shown (<option>{{item.text}}</option>') and it will select the whole objectitemas the value of the selectedoption. You could also refer to a property as the value like ({{item.text}}). Then yourng-modelwould be set to theid` value of the selected option.
The directive ng-model corresponds to the variable in the $scope of your controller that will hold the value of the selected option.
The directive ng-required allows you to check if a value has been selected. If you are using a form, you can check if the field is valid formName.ngModelName.$valid. See the docs for more details on form validation.
The directive ng-change allows you to execute a function whenever the selected option changes. You may want to pass the ng-model variable to this function as a parameter or call the variable through the $scope inside the controller.
If no default value is set, angular will add an empty option which will be removed when an option is selected.
You did use the ng-init directive to select the first option, but know that you could set the ng-model variable in your controller to the default value you would like or none.
js
Here I tried to simulate your database service by returning a promise in the case that you are doing an async request. I used the $q service to create a promise and $timeout to fake a call to the database.
myApp.factory('DbFoodCategories', function($q, $timeout) {
var foodCategories = [
{ id: 1, text: "Veggies", value: 100 },
{ id: 2, text: "Fruits", value: 50 },
{ id: 3, text: "Pasta", value: 200 },
{ id: 4, text: "Cereals", value: 250 },
{ id: 5, text: "Milk", value: 150 }
];
return {
get: function() {
var deferred = $q.defer();
// Your call to the database in place of the $timeout
$timeout(function() {
var chance = Math.random() > 0.25;
if (chance) {
// if the call is successfull, return data to controller
deferred.resolve(foodCategories);
}
else {
// if the call failed, return an error message
deferred.reject("Error");
}
}, 500);
/* // your code
_context.onReady({
success: function() {
deferred.resolve(_contect.FoodGroup);
},
error: function (error){
deferred.reject("Error");
}
});
*/
// return a promise that we will send a result soon back to the controller, but not now
return deferred.promise;
},
insert: function(item) {
/* ... */
},
update: function(item) {
/* ... */
},
remove: function(item) {
/* ... */
}
};
});
In your controller you set the variables that will be used in your view. So you can call your DbFoodCategories service to load the data into $scope.foodCategories, and set a default value in $scope.foodCategory that will be used to set the selected option.
myApp.controller('FoodSelection',function($scope, DbFoodCategories){
DbFoodCategories.get().then(
// the callback if the request was successfull
function (response) {
$scope.foodCategories = response; //response is the data we sent from the service
},
// the callback if an error occured
function (response) {
// response is the error message we set in the service
// do something like display the message
}
);
// $scope.foodCategory = defaultValue;
$scope.changeFoodCategory = function() {
alert($scope.foodCatagory.value);
}
});
I hope that this helped you understand more in detail what is happening!
See this example and how use $apply to update the data in scope.
in the new version we released a new module to support AngularJS. We've started to document how to use it, you can find the first blogpost here
With this you should be able to create your dropdown easily, no need to create the options manually. Something like this should do the trick:
myApp.controller('foodSelection',function($scope, $data) {
$scope.foodCatagories = [];
...
_context.onReady()
.then(function() {
$scope.foodCatagories = _context.FoodGroup.toLiveArray();
});
});
provided that FoodGroup has the right fields, of course