Unable to set options, such as the footer template, in Angular UI Typeahead

I am looking for a way to enhance the results page with a custom footer that includes pagination. I have noticed that there is an option to specify a footer template in the settings, but I am struggling to find examples of how to configure these options through a controller.

The desired footer template should show "Now displaying 1-{{offsetEnd}} of {{result.count}} Load More

Appreciate any assistance!

This is the code snippet I am currently using:

 < input type = "text"
 id = "search"
 name = "search"
 ng - model = "profile.selectedProfile"
 typeahead = "o.itemvalue as o.itemtext for o in getProfiles($viewValue) | filter: $viewValue"
 typeahead - input - formatter = "formatLabel($model)"
 class = "form-control"
 autocomplete = "off" />

UPDATE I transformed this into a directive and added a footer that displays the total number of records.

function findProfile() {
  return {
    restrict: 'E',
    template: '<input type="text" id="search" name="search" ng-model="selectedProfile" typeahead="o as o.itemtext for o in getProfiles($viewValue) | filter: $viewValue" typeahead-input-formatter="formatLabel($model)" class="form-control" autocomplete="off" />',
    controller: function($scope, $http) {
      $scope.itemCount = 0;
      $scope.getProfiles = function(searchtext) {
        return $http.get('http://localhost:61402/api/Profile/FindProfile?searchText=' + searchtext)
          .then(function(response) {
            $scope.itemCount = response.data.itemcount;
            return response.data.items;
          });
      }

      $scope.formatLabel = function(model) {
        return model == undefined ? '' : model.itemtext;
      }

    }
  };
}

And here is the template:

angular.run(['$templateCache',
  function($templateCache) {
    var template = '' +
      '<ul class="dropdown-menu" ng-show="isOpen()" ng-style="{top: position.top+\'px\', left: position.left+\'px\'}" style="display: block;" role="listbox" aria-hidden="{{!isOpen()}}">' +
      '<li ng-repeat="match in matches track by $index" ng-class="{active: isActive($index) }" ng-mouseenter="selectActive($index)" ng-click="selectMatch($index)" role="option" id="{{match.id}}">' +
      '<div typeahead-match index="$index" match="match" query="query" template-url="templateUrl"></div>' +
      '</li>' +
      '<li>Records Returned: {{$parent.itemCount}}</li>' +
      '</ul>';
  
    $templateCache.put('template/typeahead/typeahead-popup.html', template);
  }
])

Answer №1

Hey there! I had to come up with a creative solution to tackle this issue, but your question intrigued me.

After delving into the seldom-seen typeahead-template-url, I realized that its documentation is quite elusive. Despite the lack of clear guidelines, my prior experience with it came to the rescue. If you're looking for some insights, consider exploring this resource. Regrettably, I couldn't locate the default typeahead-template-url online today, as I failed to document its source in the past. Fortunately, I had my modified version saved.

Initially, here was the original snippet:

<a>
    <span bind-html-unsafe="match.model.label | myModelLabelFilter"></span>
</a>

This code represents the template for each displayed match in the Angular Typeahead. By incorporating a filter like myModelLabelFilter, you can customize and inject desired elements into every match.

While my approach may not have been conventional to include a single button at the end of the typeahead popup, using ng-if seemed plausible.

<a>
    <span bind-html-unsafe="match.model.label | cmcTicketingTypeaheadFilter"></span>
</a>
<div    
    ng-if="($parent.$parent.matches.length - 1) === index" 
    style="border-top:1px solid #DDDDDD;" 
>
    Example 
    <button 
        ng-click="$emit('foo', this)" 
        class="bt btn-primary" 
    >
        Click To Emit
    </button>
</div>

To avoid scrollbars, the code below is intentionally formatted oddly.

This resulted in the following output:

https://i.stack.imgur.com/3yvGr.png

You might be wondering about... the $parent.$parent.matches reference.

Essentially, we are operating within the scope of the Typeahead Directive. Within this context, we interact with three key variables: match, index, and query. The need to access a scope level where all matches are listed led me to traverse upward through parent scopes. Each scope includes the $parent attribute pointing to its parent scope.

Finally, here's your comprehensive answer! Consider making your offsetEnd variables accessible on your matches.

Instead of passing an array of strings, opt for an array of objects. This explains why my template features match.model.label. Using objects allows for capturing various user selections beyond just labels. Adding a value to these options enables you to implement paging for matches using ng-if.

Best of luck utilizing these suggestions! Hopefully, they prove beneficial. Oh, and just when I thought I had completed this response, another answer popped up!

Answer №2

To customize the appearance of the typeahead feature, you need to modify the template.

angular.module('app', ['ui.bootstrap'])
  .run(['$templateCache', function ($templateCache) {
    
    var template = '' +
      '<ul class="dropdown-menu" ng-show="isOpen()" ng-style="{top: position.top+\'px\', left: position.left+\'px\'}" style="display: block;" role="listbox" aria-hidden="{{!isOpen()}}">' +
        '<li ng-repeat="match in matches track by $index" ng-class="{active: isActive($index) }" ng-mouseenter="selectActive($index)" ng-click="selectMatch($index)" role="option" id="{{match.id}}">' +
          '<div typeahead-match index="$index" match="match" query="query" template-url="templateUrl"></div>
        '</li>'+
        '<li>The footer</li>' +
      '</ul>';
    
    $templateCache.put('template/typeahead/typeahead-popup.html', template);
  }])
  
  .controller('mainController', function($scope) {

    $scope.selected = undefined;
    $scope.states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas'];
});

In this instance, I utilized a modified version of the github-typeahead-template, where an additional li element (the footer) was added within the existing ul element. The updated template was then stored in Angular's cache for future use.

For a comprehensive example, refer to custom angular-ui bootstrap and the specific template name can be found at https://github.com/angular-ui/bootstrap/blob/0.12.1/src/typeahead/typeahead.js#L452

This technique is compatible with ui-bootstrap-tpls.js (including templates) as well as ui-bootstrap.js (without templates), although it is recommended to have the template in a separate file (e.g., typeahead-with-footer.html) instead of embedded as a string. Various options exist for achieving this, such as using grunt, a script tag, or creating the static file on your server (works specifically with ui-bootstrap.js).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Add an asterisk before each line of comment when working in a TypeScript file using the VS Code IDE

Within my VS Code workspace, I am using the Typescript language and would like to format my comments across multiple lines with a specific style (look out for the star character) /** *@desc any text * any text */ However, when I attempt to write a comm ...

An error has occurred: Noty (notification library) is not defined in this AngularJS Web Application

I am currently diving into the world of AngularJS and building a web application from scratch. As a newbie to AngularJS, I want to point out that I might be missing something crucial. An issue has arisen: After installing the Noty library (npm install no ...

Replace the typical bootstrap text class with stylish and modern google material icons

As a newcomer to the world of javascript, I acknowledge that my approach may not be ideal... I'm attempting to modify the color of a material icon upon clicking it. Essentially, I want to toggle it on and off. The challenge lies in the code's in ...

An issue arose while trying to create the perfect seed with yeoman

While working on my first Yeoman webapp using the ultimate-seed-generator, I encountered some errors that are hindering progress: C:\Users\Fidel\Desktop\Nueva carpeta\new-proyect>npm install > <a href="/cdn-cgi/l/email ...

URL from different domains

Currently, I am attempting to utilize this URL within my javascript code: Below is the snippet of my javascript code: $.ajax({ url: 'http://api.addressify.com.au/address/autoComplete', type: 'GET', crossDomain ...

The pageSize in React's Material Table does not reflect dynamic updates

Currently, I am attempting to implement pagination for material table data using TablePagination. One issue I am facing is that the pageSize property, initially defined as a state variable, does not update when the selected pageSizeOptions change. Despite ...

I'm having trouble with my Express server routes not being accessed. The browser is displaying an error message saying 'No Data Received ERR_EMPTY_RESPONSE

I've encountered an issue with my express server while setting up an email service. Despite troubleshooting and simplifying the code to a basic 'hello world' example, the problem persists. No routes are functioning properly – requests made ...

What code can I use to prompt clients to refresh JavaScript files automatically?

We are experiencing an issue where, even after pushing out updates with new JavaScript files, client browsers continue to use the cached version of the file and do not display the latest changes. While we can advise users to perform a ctrlF5 refresh during ...

Having trouble getting my asynchronous promise to work properly

I am currently working on implementing a login server function and I am struggling to understand why the promise I'm making is not being called. My setup involves using MongoDB with Mongoose as the backend, which is connected to using User.findOne. A ...

Image pop-ups that overlay text on the homepage

I'm facing an issue and I'm looking for a solution... Upon entering my homepage, I would like to display a popup image showcasing a new event so visitors can see it before accessing the website. I attempted to achieve this using JavaScript but w ...

What is the best way to use a button to hide specific divs upon clicking?

Is there a way to use a button onclick event to hide specific divs within a parent div? I've tried using .toggleClass('.AddCSSClassHere') but I'm not sure how to apply it to multiple divs. The jQuery snippet provided only allows me to h ...

Images showing Strava heat maps retrieved through API

Check out this amazing heatmap created by Strava! I'm curious about how they were able to achieve this - it seems like they are using the API to request overlay images based on the network tab. I have my own geo data, but I'm wondering how I can ...

What is the best way to handle waiting for an API call in JavaScript export?

In my Vue app, I've set up my firestore app initialization code as shown below: if (firebase.apps.length) { firebase.app() } else { firebase.initializeApp(config) } export const Firestore = firebase.firestore() export const Auth = firebase.auth() ...

Steps for converting an HTML form into a sophisticated JavaScript object

Is it possible to transform a form into a complex JavaScript object based on a structured form layout? I am not sure if there is a better way to accomplish this, but essentially what I am looking for is the following scenario: <form> <input n ...

Tips for preserving checkbox state?

I am currently working on a web application project for a clinic and laboratory, specifically focusing on sending tests. I have implemented the code below to select the test category first, followed by the test name related to that category. However, when ...

Having trouble with jQuery animate function?

I have been struggling to get my animate function to work, despite looking at multiple similar posts and making modifications to my code. My goal is to make an image of a plane move from left to right across the screen and stop halfway. Here is the code I ...

What is the most compatible JavaScript framework for openlayers?

I'm seeking guidance on selecting a front-end framework (e.g. React, Vue, Angular) that is compatible with OpenLayers for my upcoming implementation. Could you please recommend the most suitable front-end framework to work seamlessly with OpenLayers? ...

Maximizing the performance of plotting hundreds or thousands of series in a 2D scatter or line chart using Echarts

Plotting a large data set with hundreds or thousands of series using Echarts has proven to be slow and challenging to manage. If you take a look at the example code provided in this large and progressive options on single series instead of all plotted se ...

Tips for changing the TextField variant when it receives input focus and keeping the focus using Material-UI

When a user focuses on the input, I'd like to change the variant of the TextField. The code snippet below accomplishes this, but the input loses focus. This means the user has to click again on the input to focus and start typing. import React, { useS ...

Joi has decided against incorporating custom operators into their extended features

I am having trouble extending the joi class with custom operators. My goal is to validate MongoDB Ids, but when I try to use the extended object, I encounter the following error: error: uncaughtException: JoiObj.string(...).objectId is not a function TypeE ...