5

I am writing an application which UI wise is almost exactly like Google. I arrive at landing page I have a search box which on submit directs you to results page. Here you have the same search box and other directives in which you can switch between modes: eg. web, image. Currently I have:

on landing page: form with action="results.html" which passes the parameters in the url.

<form name="search" role="form" action="results.html">
    <div class="input-group input-group-search">

        <input type="text" class="form-control"  ng-model="blab" name="q" required>
        <span class="input-group-addon">
            <button class="btn-search" ng-disabled="search.$invalid">
                <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
            </button>
        </span>
        <input type="hidden" name="mode" value="web"/>
    </div>
</form>

on results I am just using ng-submit="search()" and ng-model on the input. The search box is within the searchController.

What is the right method for doing this as a custom directive, with the following behaviour:

  • On landing page on submit direct to results page
  • On results page make a search without reloading the page and change the location to the right parameters?
isherwood
  • 58,414
  • 16
  • 114
  • 157
Ela
  • 3,142
  • 6
  • 25
  • 40

1 Answers1

5

I run something similar on my site currently. I however did not wrap my search into a directive because it is it's own page.

For how I have it setup, I have a search page site.com/search (which would be your landing page for example) That page has its own controller/view SearchController. On the same page lies a separate container which can essentially list items that are inside an array. Finally, the entire page has an ApplicationController.

Now, the SearchController and ApplicationController are obviously separate and therefore cannot access each-other's properties or methods. What they can do however, is either share a factory/service or broadcast information. For the simplicity of this example we will have them share a service called SearchService.

If you still wish to use a directive, you can easily turn the SearchController into a directive and utilize the same concept for yourself.

Basic Plunkr Example Here


SearchService

The SearchService will contain useful properties and methods for searching, but all you need right now is just a simple Array to contain a list of search results.

myApp.factory('SearchService', function() {
    var SearchService;
    SearchService = {};

    // The array that will contain search results
    SearchService.arrSearchResults = [];

    return SearchService;
  }
);

ApplicationController

The ApplicationController scope will have a reference to SearchService so that you can use ng-repeat and list out the actual contents of the search results.

myApp.controller('ApplicationController', [
  '$scope', 'SearchService', function($scope, SearchService) {

      // Create a reference to the SearchService and add it to the 
      // $scope so it will be available on the page
      $scope.searchService = SearchService;

  }
]);

SearchController

The SearchController scope will also have a reference to SearchService so that it can modify the SearchService.arrSearchResults array, thus altering what will be displayed on the page. It will also contain methods to interact with the form.

It will also alter the URL location when a search is executed.

myApp.controller('SearchController', ['$scope', 'SearchService', '$http', '$location', function($scope, SearchService, $http, $location) {

    // Your search input
    $scope.blab = "";

    // Your search function
    $scope.search = function() {

    // Make sure blab has content (always good to double check)
    if($scope.blab != "") {

        // Alter URL to show new request
        $location.search('q', $scope.blab);

        // Make a GET request to your URL that will 
        // return data for you to populate
        $http.get('/someUrl').
            success(function(data, status, headers, config) {

                // this callback will be called asynchronously
                // when the response is available

                alert("Search results found!");

                // Assuming the data returned is a list of items
                // or object items
                // (i.e. [ "Search Result1", "Search Result2", ... ]
                SearchService.arrSearchResults = data;

            }).
            error(function(data, status, headers, config) {

                // called asynchronously if an error occurs
                // or server returns response with an error status.

                alert("Something failed! No results found!");

                // Empty the array of search results 
                // to show no results
                SearchService.arrSearchResults = [];
            });
    };
}]);

The Page

<!doctype html>
<head>
    <title>Search Example Page</title>

    <!-- Insert Angular.JS source files here -->
</head>
<body ng-controller="ApplicationController" ng-app="myApp">

    <!-- ngView -->
    <div role="main" data-ng-view>

    </div>

    <!-- Search Results -->
    <div ng-repeat="searchItem in searchService.arrSearchResults">

        <p style="border-bottom: 2px solid #000">Search Result: <br/>{{searchItem}}</p>

    </div>

</body>
</html>

Tabs

For switching the type of search result (web, image, etc) you can create a variable within the SearchService that controls the state of the search, and thus what type of search to run.

SearchService.typeOfSearch = "web"; This sets the state to web and thus can be interacted within the page and app.

You can then have various ng-repeat throughout the page all showing results for different states:

<!-- Search Results - Web -->
<div ng-if="searchService.typeOfSearch='web'" ng-repeat="searchItem in searchService.arrSearchResults">

    <p style="border-bottom: 2px solid blue">Search Result: <br/>{{searchItem}}</p>

</div>


<!-- Search Results - Image -->
<div ng-if="searchService.typeOfSearch='image'" ng-repeat="searchItem in searchService.arrSearchResults">

    <p style="border-bottom: 2px solid red">Search Result: <br/>{{searchItem}}</p>

</div>

I have updated the Plunkr to demonstrate.

Pixxl
  • 945
  • 10
  • 18
  • Thanks, I didn't think about this way: search <- service -> view. What about the tabs? Currently I have them having an ng-include for each, since the way I display them defers each time, however this means no page reload. My server call for search has just a "mode" parameter. – Ela Feb 18 '15 at 14:35
  • If my answer has helped you, please select it. As far as tabs go (going to web search, image search, etc...) You can essentially have a set state in the `ApplicationController` which can be changed by your app. That state can then load different results for your searches. I'll adjust my answer to show an example... – Pixxl Feb 19 '15 at 17:46
  • @ManBearPixel, i have very similar requirement for my project. Here i did not understand where on-change event is handled for search text? also from where suggestions are populating. Can please ellobrate on it. – Devesh Agrawal Apr 10 '15 at 03:53
  • Hey @DeveshAgrawal as far as the on-change event firing from the search text input I don't think I have that implemented here, but there are two ways to go about it. **$scope.$watch** You can use the `scope` to listen to changes to a variable, in this case it would be `$scope.$watch('q', function(newVal, oldVal) { ... });` [AngularJS Scope](https://docs.angularjs.org/api/ng/type/$rootScope.Scope) **ng-change** The other way to watch for text input changes would be to use ng-change="aScopeFunc()" [AngularJS ngChange](https://docs.angularjs.org/api/ng/directive/ngChange) – Pixxl Apr 14 '15 at 15:18
  • @DeveshAgrawal The suggestions are populated when the user hits the _Search_ button which, depending on the search state, will either grab the results from `results-web.json` or `results-image.json`. The Plunkr example doesn't have any logic to apply the search term to the actual search as this is just an example of demonstration, but ideally you would have a back-end service setup to run a query based on the search term and return back a JSON Object with the appropriate results. Hope this helps you Devesh! – Pixxl Apr 14 '15 at 15:24