I have a search 'page' in my AngularJS app which essentially consists of a view that holds the search form (and displays the results) and a controller which handles the search request. When the user types in a search query and hits 'Search', the $scope.submit() method is called and I can see the results properly. However, when the user clicks on a result and then goes back to the search page, it is blank. I thought of implementing a $cookieStore-based solution so that the query is stored in a cookie and whenever the user goes back to the search page, it automatically re-runs the previous search so they don't have to do it manually. Problem is, the model updates (search gets run from cookieStore value) but the view stays the same (blank). Here's a sample of my controller:
.controller('SearchCtrl', ['$scope', '$http', '$cookieStore','authService', function($scope, $http, $cookieStore, authService) {
var submitted = false;
$scope.submit = function(query){
$cookieStore.query = query;
submitted = true;
$http.jsonp(url).success(function(data) {
$scope.searchResults = data;
});
}
/*
Rerun query if user has pressed "back" or "home" button automatically:
*/
if(!submitted && $cookieStore.query){
console.log("submitting query from cookie store", $cookieStore.query);
$scope.submit($cookieStore.query);
}
... });
I tried using $scope.$apply() after the auto-search but still no joy. The view just won't update. Any hints you guys could give me? Cheers
You should place $scope.$apply at the end of your callback function. It's because $http makes an async AJAX call and by the time response comes back Angular is already done auto-$applying changes. So when you check the model you see the difference but since Angular is no longer $applying the difference cannot be seen on the view.
So when you add $scope.$apply you will have something like this:
.controller('SearchCtrl', ['$scope', '$http', '$cookieStore','authService', function($scope, $http, $cookieStore, authService) {
var submitted = false;
$scope.submit = function(query){
$cookieStore.query = query;
submitted = true;
$http.jsonp(url).success(function(data) {
$scope.searchResults = data;
$scope.$apply();
});
}
/*
Rerun query if user has pressed "back" or "home" button automatically:
*/
if(!submitted && $cookieStore.query){
console.log("submitting query from cookie store", $cookieStore.query);
$scope.submit($cookieStore.query);
}
... });
Related
Hope some of you can provide me with some suggestions on how to Query Data From Firebase into my HTML Page.
Controller
.controller('cloudCtrl', ['$scope', '$stateParams', '$firebaseArray' ,// $stateParams.parameterName
function ($scope, $stateParams, $firebaseArray) {
var ref2 = firebase.database().ref().child("info");
var sync = $firebaseArray(ref2);
console.log(sync.toString());
sync.orderBychild('name').endAt(3).on('child_added', function(snap){
console.log('added', snap.val())
})
}])
HTML5 File
<div ng-controller="cloudCtrl">
<button ng-click="Load()">Load User</button>
</div>
Since you are using angularfire, you can do it this way:
$scope.load = function() {
$scope.result = firebase.database().ref().child("info").orderByChild('name').endAt(3);
}
Be careful concerning the camelCase on orderByChild.
You only need to watch the data if you want an event to occur when a child is added. For example, send a notification when a new message is available. Otherwise the database works in realtime, so if you modify a the name in info (directly in the firebase console) it will be available and updated in your scope.
There is one other way to do this which might come in handy while you're preparing your app:
$firebaseArray(yourRef).$loaded().then(function(result) {
$scope.result = result;
})
This will handle the promise while you're fetching the data. That might be useful if you want to show a loader while fetching the data which you would show before that function and hide once it is done.
Hope it helps !
Could you please tell me how to send data from one view to another using state. I don't want to use factory or service. I need to send the data using url and get the data from url and display it on view.
I have one field name in my first View. I want to display on the second view whatever user enters in the input field. On button click, I need to send it to another view. I am able to go to the next view but how to send the data?
Plunker
http://plnkr.co/edit/iDlzhzkz0pJKN2f2CZZe?p=preview
var loginCntrl = function($scope, $location, $state) {
$scope.testClick = function() {
$state.go("navigation2");
}
$scope.name = "";
/*$scope.fullname = function() {
return $scope.firstname + $scope.lastname;
};*/
}
$state.go can have a parameters object to pass on to the view
Check here: https://github.com/angular-ui/ui-router/wiki/Quick-Reference#stategoto--toparams--options
$state.go("State", {Hello:"Hi!"});
You can then pick up those params on the view controller using $stateParams
app.controller("SomeController", function($scope, $stateParams){
$scope.NewHello = $stateParams.Hello;
})
You will also need to amend the URL to accept this parameter:
url:"/someurl/{Hello}
I am newbie for angularjs.I have list of persons and each person have edit and delete button. when i click to edit button ng-dialog box was open and show person details and person can change and save information on database,behind save button ajax call trigger and update information on database.
Updating information on database work well but on UI side my view doesn't reflect my database changes.
I had tried to apply "$scope.$apply();" method but i got error message "$digest already in progress".
Please help me,how can refresh my scope after ajax call.
You can use shared service for that and broadcast any event through this service. Broadcasted event can be listened in any controller with $scope.$on.
For example:
angular.module("app", []).factory("sharedService", function($rootScope){
var mySharedService = {};
mySharedService.values = {};
mySharedService.personWasUpdated = function(){
$rootScope.$broadcast('update');
}
return mySharedService;
});
Ctrl for person editing.
app.controller('personEditController', ['$scope', 'sharedService', '$http', function ($scope, sharedService, $http) {
$scope.updatePerson = function(newPerson){
$http.post("../some URL/..", {person: newPerson})
.success(function(data){
sharedService.personWasUpdated(); //event broadcasing
})
};
}
Ctrl for displaying list of persons.
app.controller('personController', ['$scope', 'sharedService', '$http', function ($scope, sharedService, $http) {
var loadPersonsData = function(){
$http.get("../some URL/..").
.success(function(data){
$scope.persons = data;
})
};
loadPersonsData(); //first load
$scope.$on('update', function () {
loadPersonsData(); // load after update of any person
});
}
Try with $scope.$digest(); or use $http instead jQuery ajax or others
I have a AngularJS app with a service that load a HTTP request, that works all fine, but...
When my app is offline at the beginning, i show a "offline" page with a retry button, when i click the button and the APP is online I need the service to load the data.
The problem is that nothing happen when I click the button, the online check works fine but the web service is never called :(
my service:
.service('webService', function ($http, $q){
var defferer = $q.defer()
var webservice_url = "http://mywebservice_url/";
$http.get(webservice_url+"?action=get_settings").success(function(data) {
defferer.resolve(data);
});
return defferer.promise;
})
my controller:
.controller('NetworkCtrl', function($scope, $location, $timeout, webService) {
$("#tryagain-button").click(function(e) {
e.preventDefault();
if(checkifonline()) {
webService.then(function(data) {
$scope.data = data;
});
}
});
})
First of all, using jQuery within an controller is absolutely not how angularjs works. Use the ng-click directive. Even if your service would be implemented correctly, it wouldn't work since AngularJS will not get notified about model changes in the scope (you would need to use $apply, but just stick to the ng-click directive)
Second, the service function takes a constructor function. Within this constructor you're making an http request (while you're offline) and the promise is resolved. You will never make a new request, since the service always retuns the same promise. Your service should look like:
.service('webService', function ($http){
var webservice_url = "http://mywebservice_url/";
this.getSettings = function(){
return $http.get(webservice_url+"?action=get_settings");
};
})
and your controller:
.controller('NetworkCtrl', function($scope, $location, $timeout, webService) {
$scope.onClick = function(){
webService.getSettings().success(function(data){
$scope.data = data;
}
}
})
and your HTML button:
<button ng-click="onClick()">reload</button>
My AngularJS controller is calling an API to get a list of members. The API can be queried with multiple filters, like age range, name search, zipcode, etc.
What I am trying to accomplish is to make the user feel like the search is really fast. So while the user is filtering, I am $watch'ing the filters for changes. When a filter changes I immediately do a new search API call, instead of waiting for the user to click "search".
The idea is that when the user finishes filtering and clicks "search", the system should already be finished searching and can just output the search results.
The problem: When a user clicks "search" and the publish() function is called, I have to make sure that no API search is currently ongoing and if one is, wait for it to finish. I then publish the search results from the hidden memberslist.temp to the visible memberslist.members.
// Current code works, except the publish function. See the TODO:
app.controller('SearchCtrl', ['$scope', 'Restangular', '$timeout', function($scope, Restangular, $timeout) {
// Pushes prefetched search results over to the visible search results
// TODO: Check if search is ongoing...
$scope.publish = function() {
$scope.memberslist.members = $scope.memberslist.temp;
};
// Watch filters for changes
var searchTimer = false;
var previousSearch = [$scope.name, $scope.minAge, $scope.maxAge];
$scope.$watch('[name, minAge, maxAge]', function(newVal, oldVal, scope){
if (searchTimer) {
$timeout.cancel(searchTimer);
}
// Do search only after the user has stopped typing for 400 ms
searchTimer = $timeout(function(){
if (!_.isEqual(newVal, previousSearch)) {
previousSearch = newVal;
scope.search();
}
}, 400);
}, true);
$scope.search = function() {
var query_params = {
name: $scope.name,
price_min: $scope.minAge,
price_max: $scope.maxAge
};
Restangular.all('members').getList(query_params)
.then(function(members){
$scope.memberslist.temp = members;
});
};
}]);
My first thought was to set a variable like isSearching = true, then set that back to false once the search call returns it's results. Can't seem to get it to work though.
Perhaps something like:
$scope.$watch('!is_searching && publishing', function(newVal){
if (newVal) {
$scope.memberslist.members = $scope.memberslist.temp;
$scope.publishing = false;
}
})
Set "is_searching" to true on the scope when the search starts, and set it to false when it is done. Set "publishing" on the scope when the search button is clicked.
That should give you the desired behavior. Publish right away if no search is running, otherwise wait until search is complete.