Have a small search app using Elasticsearch and AngularJS. I'm using $state.go() in my search() on my ng-submit button. searchTerms is my ng-model on the input.
I have 2 controllers, homeCtrl and searchCtrl. homeCtrl is for homepage which is just a search box and provides autocomplete functionality. searchCtrl is for results page and has same search box and provides for results area.
When I have $state.go() like this:
$state.go('search', {q: searchTerms});
It solved a problem I was having, which was
http://localhost:8000/app/search?q=searchTerms
INSTEAD of
http://localhost:8000/app/search?q=userTypedInput
So now the url functions correctly, but the search results do not display...?
When I have
$state.go('search', {q: 'searchTerms'});
The search results display BUT the url does not function as desired.
So basically what I'm asking is how can I get my url to function as desired which is
http://localhost:8000/app/search?q=userTypedInput
AND still have the search results display?
UPDATE
These are my states for ui router
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home/home.html', controller: 'homeCtrl'})
.state('search', {
url: '/search?q',
views: {
'' : { templateUrl: 'search/search.html', controller: 'searchCtrl' }
//add more views here when necessary
}
});
searchCtrl
I have this at the top
'use strict';
angular.module("searchApp.search", ['ngAnimate'])
.controller('searchCtrl', ['$scope', '$sce', '$stateParams', '$state', 'searchService', function($scope, $sce, $stateParams, $state, searchService) {
$scope.searchTerms = $stateParams.searchTerms || null;
and this is search(), which contains the $state.go()
$scope.search = function() {
resetResults();
var searchTerms = $scope.searchTerms;
if (searchTerms) {
$scope.results.searchTerms = searchTerms;
} else {
return;
}
getResults();//calls searchService which does the searching
$state.go('search', {q: searchTerms});
};
var getResults = function() {
$scope.isSearching = true;
searchService.search($scope.results.searchTerms,$scope.currentPage,...
I'm trying to get the url to be
http://localhost:8000/app/search?q=userTypedInput
and have the results display as well.
In your state config you use the parameter name of q to pass the search query. This is the name, you also need to use when accessing the parameter from $stateParams in your searchCtrl. In the code shown above, your query will always be null, because you access the parameter named searchQuery which doesn't exist.
Related
I am new to angular js. I have search page with input text box to search for customerId but I want to add a functionality where I can search based on url string as well.
For example, My url is :
http://localhost:8080/#/search
But I need something like
http://localhost:8080/#/search?ACC34ff
http://localhost:8080/#/search?CustomerId so that I can search based on customerId in url also
Can some one tell how can I add query string ?
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/home', {
templateUrl: 'partials/home.html',
controller: 'homePageCtrl',
reloadOnSearch: true
}).when('/features', {
templateUrl: 'partials/features.html',
controller: 'featuresCtrl',
reloadOnSearch: false
}).when('/search', {
templateUrl: 'partials/search.html',
controller: 'searchCtrl',
reloadOnSearch: false
}).otherwise({
redirectTo: '/home'
});
}]);
Controller :
appControllers.controller('searchCtrl', ['$scope','$route','$filter', '$http', '$location','$window','$timeout',
function($scope, $route, $filter, $http, $location, $window, $timeout) {
$scope.searchCustomerFeatures = function () {
if($scope.customerId != null) {
$http.get('/getCustomerFeatures.do', {params: {'customerId': $scope.customerId}}).success(function (data) {
$scope.featuresJson = angular.toJson(data, true);
});
}
}
}]);
Html :
<li ng-class="{active: isActive('/search')}" style="margin-left: 100px; text-decoration-color: black; font-size: 20px">
Search
</li >
Search page :
Thanks
Firstly, I can't believe you haven't got more answers because there are many ways to pass and retrieve a variable over the url, each being slight variations of 2 main ways.
As part of a Query String (as per your request)
As a Route Parameter (also worth mentioning)
The subsequent examples assume that you have a text input for customer id as follows:
<input type="text" ng-model="customerId" />
1) How to pass customerId as part of a Query String
Append ?cId={{ customerId }} to your link as follows:
Search
Now when you click on the link you will be taken to a url such as:
http://localhost:8080/#/search?cId=ACC34ff
You can then pick the cId parameter up in the controller by using the $location service.
app.controller('searchCtrl', function($scope, $location){
var qsCustomerId = $location.search().cId;
// Do what you want with qsCustomerId here...
});
2) How to pass customerId as a Route Parameter
Create a new route that specifies a new cId route parameter:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/search/:cId', {
templateUrl: 'partials/search.html',
controller: 'searchCtrl',
reloadOnSearch: false
})
}]);
Append /{{ customerId }} to your link as follows:
Search
Now when you click on the link you will be taken to a url such as:
http://localhost:8080/#/search/ACC34ff
You can pick the cId parameter up in the controller using the $routeParams service.
app.controller('searchCtrl', function($scope, $routeParmas){
var rpCustomerId = $routeParmas.cId;
// Do what you want with rpCustomerId here...
});
All you need is to pass the customerId as a parameter.
.when('/Search', {
templateUrl: function (params) { return 'partials/search?customer=' + params.CustomerId; }
})
In the follow link there is also an explanation on how to pass multiple parameters, in case you need:
https://stackoverflow.com/a/35967896/5988277
Based on this tutorial, I have as my parent state a list of people. When I click on one of them, a new view is created in order to show the details for that person. In my URL I use the ID for that person, so it's rather easy to go and fetch the ID to be used in the child state. The problem is that I also want to pass information such as the name, e-mail, age, etc.
The code is as follows:
My routes:
angular
.module('appRoutes', ["ui.router"])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
var TalentForceState_seeProfile = {
name: 'students',
url: '/seeProfile',
templateUrl: 'public/templates/talentforce_template.html',
controller: 'People_Controller'
}
var singleStudent = {
name: 'student',
parent: 'students',
url: '/:personId',
templateUrl: 'public/templates/person_template.html',
controller: 'Person_Controller'
}
....
Then, the controller for People:
talentforceApp
.controller('People_Controller', ['$scope', '$state', '$stateParams', 'StudentService', function($scope, $state, $stateParams, StudentService) {
StudentService.query().$promise.then(function(data) {
$scope.students = data;
});
}]);
Then, the controller for Person:
talentforceApp
.controller('Person_Controller', ['$scope', '$state', '$stateParams', 'StudentService', function($scope, $state, $stateParams, StudentService) {
$scope.student_id = $stateParams.personId;
console.log($stateParams)
}]);
Also, here's the HTML for the Person:
<div ng-controller="Person_Controller">
<h3>A person!</h3>
<div>Name: {{student_name}}</div>
<div>Id: {{student_id}}</div>
<button ui-sref="students">Close</button>
</div>
Information such as student_name is what I can't seem to pass from the parent state
I tried using solutions like this, that use $state.go, or this, that use params, but it always gives me errors such as param values not valid for state or the variables are undefined.
Any solution for this problem?
You can use angular's state resolve to achieve your requirement in a better way. Although there are many choices for it.
Procedure:
When your parent state loads, you query all the people in an API call.
In that response, I am assigning the response to an instance of a service using studentService.addStudents($scope.students); where addStudents is a function in the service.
Now, when you navigate to the detail of a person, I have used resolve which fetches the stored data from the service using the function studentService.getStudents() and returns a person object to the controller.
Use that person object directly in the person controller by injecting the resolve variable
I prefer using resolve. I will tell you why.
Here is the resolve you can use:
resolve: {
student: function(studentService, $stateParams) {
return studentService.getStudents().find(function(student) {
return student.id === $stateParams.personId;
});
}
}
You will add a service studentService or you can extend your own service.
Service:
talentforceApp.service('studentService', function(){
vm = this;
vm.students = []
this.addStudents = function(students) {
vm.students = students;
}
this.getStudents = function() {
return vm.students;
}
});
I added addStudents and getStudents methods to it.
One method add students to array and the other get the data of a studenr.
People Controller revised:
talentforceApp
.controller('People_Controller', ['$scope', '$state', '$stateParams', 'StudentService', function($scope, $state, $stateParams, StudentService,studentService) {
StudentService.query().$promise.then(function(data) {
$scope.students = data;
studentService.addStudents($scope.students); // this will create a students array in service instance
});
}]);
I assigned $scope.students to the service instance.
routes revised:
var TalentForceState_seeProfile = {
name: 'students',
url: '/seeProfile',
templateUrl: 'public/templates/talentforce_template.html',
controller: 'People_Controller'
}
var singleStudent = {
name: 'student',
parent: 'students',
url: '/:personId',
templateUrl: 'public/templates/person_template.html',
controller: 'Person_Controller',
resolve: {
student: function(studentService, $stateParams) {
return studentService.getStudents.find(function(student) {
return student.id === $stateParams.personId;
});
}
}
}
Now, you can use student from resolve into your controller, as a dependency.
person controller revised:
talentforceApp
.controller('Person_Controller', ['$scope', '$state', '$stateParams', 'StudentService',student, function($scope, $state, $stateParams, StudentService,student) {
$scope.student_id = $stateParams.personId;
console.log($stateParams)
$scope.student = student // this line add student to scope
console.log($scope.student)
}]);
Check your student object in the view:
View:
<div ng-controller="Person_Controller">
<h3>A person!</h3>
{{student}}
<div>Name: {{student_name}}</div>
<div>Id: {{student_id}}</div>
<button ui-sref="students">Close</button>
</div>
here is why I prefer to use resolve and its advantages
You can't pass a large object with nested properties with $state.go. You can use event: broadcast, emit. Creating a service that hold and share data to your controllers is a better way.
There is a partially working example of my issue at http://nwlink.com/~geoffrey/routing/default.html
var routingInterface = angular.module("routingInterface", ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state("first",
{
url: "",
template: '<h1>{{title}}</h1><timer-control action="second" wait="10" ></timer-control>' +
'<p>This page is supposed to change to another in ten seconds</p>',
controller: function($scope) {
$scope.title = "Welcome to Routing";
}
});
$stateProvider.state("second",
{
url: "",
template: '<h1>{{title}}<h2><p>This page is supposed to be displayed after the routing works</p>',
controller: function($scope) {
$scope.title = "Second page for routing";
}
});
});
State "first" always comes up no matter which hash is displayed. I thought I was copying syntax from an example correctly, but I'm not getting something right.
There's a directive on the first view:
routingController.directive('timerControl',
[
'$timeout', '$state', '$location',
function($timeout, $state, $location) {
return {
scope: {
action: "#",
wait: "#"
},
link: function($scope) {
if (!$scope.wait) {
$scope.wait = 30;
}
var tOut = $timeout(function() {
$timeout.cancel(tOut);
//this doesn't work:
// $location.hash($scope.action);
// does work but doesn't put a hash on the url
// like I expected
$state.go($scope.action);
},
Number($scope.wait) * 1000);
},
template: '<span class="ng-hide"></span>'
};
}
]);
This does work put a new hash on the url to navigate to the new view, but it angular adds a second hash mark. But even if I type it in correctly in the url, something (the browser? or angularJS?) is adding a "/" to whatever I type. And I never ever display anything other than the first view.
I need a way to have views be unique but still expressed on the url somehow. If I have to use parameters that would also be ok. I expect that there will have to be parameters for some of the views.
I was actually very close to the right answer.
var routingInterface = angular.module("routingInterface", ['ui.router'])
.config(function ($stateProvider, $urlRouterProvider) {
//this was the first omission
//it allows the first page to render even without the hash
$urlRouterProvider.otherwise("first");
$stateProvider.state("first",
{
url: "/first", // this is what puts the hash on the Url
// and responds to the hash
template: '<h1>{{title}}</h1><timer-control action="second" wait="10" ></timer-control>' +
'<p>This page is supposed to change to another in ten seconds</p>',
controller: function ($scope) {
$scope.title = "Welcome to Routing";
}
});
$stateProvider.state("second",
{
url: "/second", //this is what puts the hash on the Url and
//and responds to the hash
template: '<h1>{{title}}</h1><p>This page is supposed to be displayed after the routing works</p>',
controller: function ($scope) {
$scope.title = "Second page for routing";
}
});
});
After login I want to pass the user details to dashboard?How it possible in angular js?
Login.js
mySchoolApp.controller('loginController', ['$scope', '$http', function($scope, $http) {
this.loginForm = function() {
let encodedString = 'uname=' +this.username +'&pwrd=' +this.password;
sessionStorage.user = encodedString;
console.log(sessionStorage.user)
window.location.href = 'dashboard.html';
}
}]);
In console I'm getting the value.
How to get the user details in dashboard.html page?
You should use ng-route to achieve this.Angular isn't designed to work like this
Here is sample
$stateProvider
.state('app', {
abstract: true,
url: "",
template: '<ui-view/>'
})
.state('app.home', {
url: "/",
templateUrl: "partials/main_page.html",
resolve: {
skipIfLoggedIn: skipIfLoggedIn
}
}).state('app.dashboard', {
url: "/dashboard",
templateUrl: "partials/dashboard.html",
controller: 'DashboardCtrl',
activePage:'dashboard',
resolve: {
loginRequired: loginRequired
}
You can store it in a localstorage.So you can use angular-local-storage Angular module for that.
How to set :
myApp.controller('MainCtrl', function($scope, localStorageService) {
//...
function submit(key, val) {
return localStorageService.set(key, val);
}
//...
});
How to Get :
myApp.controller('MainCtrl', function($scope, localStorageService) {
//...
function getItem(key) {
return localStorageService.get(key);
}
//...
});
You should use router module ui-router or ng-router in order to use angualrjs logic in that sense but then your pages are going to be loaded via ajax and regular session http authentication can not be applied.
If that's the case then use angular service provider and let me know to edit my answer.
If you'd like to keep data across pages and not using database or server.
Then what is left as options are: sessionStorage and localStorage.
The localStorage keeps data permanently until browser cache deletes it while the other one obviously for the session.
sessionStorage.setItem('myCat', 'Tom');
If you want to keep js collection like object or array first stringify it:
var user = {pass:'moo', name: 'boo'};
sessionStorage.setItem('userDetais', JSON.stringify(user));
Using angular ui-router I'm trying to use $state.go() to change to the blogEdit state after creating a new entry with blogCreate to continue editing after saving. When I click to save and trigger addPost() method, it doesnt redirect correctly and I see /#/null as the route in the address bar instead of the expected /blog/post/:postId/edit.
blogModule.controller('PostCreateController', ['$scope', '$state', '$stateParams', 'PostResource',
function ($scope, $state, $stateParams, PostResource) {
$scope.post = new PostResource();
$scope.addPost = function () {
$scope.post.$save(function () {
$state.go('blogEdit', {postId: $stateParams.postId}); // THIS SHOULD REDIRECT TO CONTINUE EDITING POST
});
}
}
]);
blogModule.controller('PostEditController', ['$scope', '$stateParams', 'PostResource',
function ($scope, $stateParams, PostResource) {
$scope.post = PostResource.get({postId: $stateParams.postId});
$scope.updatePost = function () {
$scope.post.$update({postId: $stateParams.postId});
}
}
]);
State route configuration:
var app = angular.module('app', [
'ui.router',
'blogModule'
]);
app.config(['$stateProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('blog', {
url: '/blog',
templateUrl: 'app/blog/view/blog-list.html',
controller: 'PostListController'
})
.state('blogView', {
url: '/blog/post/{postId:[0-9]}',
templateUrl: 'app/blog/view/blog-detail.html',
controller: 'PostViewController'
})
.state('blogCreate', {
url: '/blog/post/new',
templateUrl: 'app/blog/view/blog-create.html',
controller: 'PostCreateController'
})
.state('blogEdit', {
url: '/blog/post/{postId:[0-9]}/edit',
templateUrl: 'app/blog/view/blog-edit.html',
controller: 'PostEditController'
});
}]);
It seems to do this regardless of what state I try to change to.
I suppose you are saving your post on backend. When you perform save (PUT) operation your backend should return you some response. The response should be like HTTP 201 Entity created and there should be location attribute set (f.e. http://example.com/blog/post/1). Then you can get the id from location header like this:
$scope.post.$save(function (createdPost, headers) {
var postId = headers.location.split("/").pop();
$state.go('blogEdit', {postId: postId});
});
Another way is to just ignore headers and return json response from your backend. F.e. {"postId": 1, "title": "New post", ...}. Then you can do something like:
$scope.post.$save(function (createdPost) {
$state.go('blogEdit', {postId: createdPost.postId});
});
The most important is to know API of your backend (what "it returns").