├── .gitignore ├── README.markdown ├── bower.json ├── css └── screen.css ├── index.html └── js └── script.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | A sample recipe search. 2 | 3 | ## Installing 4 | 5 | You'll need [bower](http://bower.io/) to install the javascript dependencies. 6 | After you get it, just run 7 | 8 | bower install 9 | 10 | in the root directory. 11 | 12 | You'll also need elasticsearch loaded up with recipes and accepting connections on 13 | localhost:9200 for this example. 14 | 15 | When all those ducks are in a row, just open index.html in a browser. 16 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openrecipesearch-demo", 3 | "version": "0.0.0", 4 | "authors": [ 5 | "Adam " 6 | ], 7 | "license": "MIT", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "dependencies": { 16 | "angular": "~1.2.15", 17 | "elasticsearch": "~2.1.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /css/screen.css: -------------------------------------------------------------------------------- 1 | /* Base styles */ 2 | 3 | body{ 4 | font-family: "Arial"; 5 | color: #444; 6 | font-size: 18px; 7 | line-height: 24px; 8 | } 9 | 10 | p, li, h1, h2, h3, h4, h5, h6{ 11 | margin-top: 24px; 12 | line-height: 24px; 13 | } 14 | 15 | li+li{ 16 | margin-top: 0px; 17 | } 18 | 19 | .container{ 20 | width: 728px; 21 | margin: 0px auto; 22 | } 23 | 24 | /* Block styles */ 25 | 26 | header, section, footer{ 27 | margin: 48px 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MyOpenRecipes: An openrecipe search 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

OpenRecipe Search

16 |
17 |
18 |
19 | 20 | 21 |
22 |
23 |
24 |
No results
25 | 37 |
38 | More... 39 |
40 |
41 | 47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /js/script.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create the module. Set it up to use html5 mode. 3 | */ 4 | window.MyOpenRecipes = angular.module('myOpenRecipes', ['elasticsearch'], 5 | ['$locationProvider', function($locationProvider){ 6 | $locationProvider.html5Mode(true); 7 | }] 8 | ); 9 | 10 | /** 11 | * Create a service to power calls to Elasticsearch. We only need to 12 | * use the _search endpoint. 13 | */ 14 | MyOpenRecipes.factory('recipeService', 15 | ['$q', 'esFactory', '$location', function($q, elasticsearch, $location){ 16 | var client = elasticsearch({ 17 | host: $location.host() + ":9200" 18 | }); 19 | 20 | /** 21 | * Given a term and an offset, load another round of 10 recipes. 22 | * 23 | * Returns a promise. 24 | */ 25 | var search = function(term, offset){ 26 | var deferred = $q.defer(); 27 | var query = { 28 | "match": { 29 | "_all": term 30 | } 31 | }; 32 | 33 | client.search({ 34 | "index": 'recipes', 35 | "type": 'recipe', 36 | "body": { 37 | "size": 10, 38 | "from": (offset || 0) * 10, 39 | "query": query 40 | } 41 | }).then(function(result) { 42 | var ii = 0, hits_in, hits_out = []; 43 | hits_in = (result.hits || {}).hits || []; 44 | for(;ii < hits_in.length; ii++){ 45 | hits_out.push(hits_in[ii]._source); 46 | } 47 | deferred.resolve(hits_out); 48 | }, deferred.reject); 49 | 50 | return deferred.promise; 51 | }; 52 | 53 | 54 | return { 55 | "search": search 56 | }; 57 | }] 58 | ); 59 | 60 | /** 61 | * Create a controller to interact with the UI. 62 | */ 63 | MyOpenRecipes.controller('recipeCtrl', 64 | ['recipeService', '$scope', '$location', function(recipes, $scope, $location){ 65 | // Provide some nice initial choices 66 | var initChoices = [ 67 | "rendang", 68 | "nasi goreng", 69 | "pad thai", 70 | "pizza", 71 | "lasagne", 72 | "ice cream", 73 | "schnitzel", 74 | "hummous" 75 | ]; 76 | var idx = Math.floor(Math.random() * initChoices.length); 77 | 78 | // Initialize the scope defaults. 79 | $scope.recipes = []; // An array of recipe results to display 80 | $scope.page = 0; // A counter to keep track of our current page 81 | $scope.allResults = false; // Whether or not all results have been found. 82 | 83 | // And, a random search term to start if none was present on page load. 84 | $scope.searchTerm = $location.search().q || initChoices[idx]; 85 | 86 | /** 87 | * A fresh search. Reset the scope variables to their defaults, set 88 | * the q query parameter, and load more results. 89 | */ 90 | $scope.search = function(){ 91 | $scope.page = 0; 92 | $scope.recipes = []; 93 | $scope.allResults = false; 94 | $location.search({'q': $scope.searchTerm}); 95 | $scope.loadMore(); 96 | }; 97 | 98 | /** 99 | * Load the next page of results, incrementing the page counter. 100 | * When query is finished, push results onto $scope.recipes and decide 101 | * whether all results have been returned (i.e. were 10 results returned?) 102 | */ 103 | $scope.loadMore = function(){ 104 | recipes.search($scope.searchTerm, $scope.page++).then(function(results){ 105 | if(results.length !== 10){ 106 | $scope.allResults = true; 107 | } 108 | 109 | var ii = 0; 110 | for(;ii < results.length; ii++){ 111 | $scope.recipes.push(results[ii]); 112 | } 113 | }); 114 | }; 115 | 116 | // Load results on first run 117 | $scope.loadMore(); 118 | }] 119 | ); 120 | --------------------------------------------------------------------------------