I just built a small search app for movies using AngularJS and Elasticsearch. I used the AngularJS UI Bootstrap Typeahead for autocomplete and in testing noticed something about user interaction.
Say I want to search for actors named Tom. I type in "tom" in the search input and 5 suggestions appear - fine. However, it won't let me just search for "tom" if all I do is press Enter on the keyboard. It automatically selects the first suggestion in the dropdown. IT WILL just search for "tom" if I just click on the submit button. My form markup is below - where am I going wrong?
I want to allow my users to be able to search for the queries they enter (when they press Enter) without being limited to just the suggestions provided...
<div class="col-sm-3 col-md-6 pull-left" style="border: 1px solid red;"><form name="q" ng-submit="vm.search()" class="navbar-form" role="search">
<div class="input-group input-group-md">
<input type="text" ng-model="vm.searchTerms" class="form-control input-md" placeholder="{{ vm.searchTerms }}" name="q" typeahead-show-hint="true" uib-typeahead="query for query in vm.getSuggestions($viewValue)" typeahead-on-select="vm.search($item)">
<span class="input-group-btn">
<button class="btn btn-primary btn-md" type="submit" id="results-search-btn" ng-submit="vm.search()"><i class="fa fa-search fa-lg"></i>
</button>
</span>
</div>
It is automatically selecting the first result. So when you press enter it already has focus on that first result. You can configure the angular ui typeahead to not automatically select the first result like so:
typeahead-focus-first="false"
see their documentation for further information:
https://angular-ui.github.io/bootstrap/#/typeahead
Related
I have a simple bootstrap form . For sake of example i have a input field and a dropdown. I want to enable the save button only when the change is made. In order to do that, i made the save button enable only if the form is dirty.
The problem is - When i change the input field it works, the button gets enabled, where as when i change the dropdown, which is basically selecting the list item, the form does not identify it as dirty and hence it is still disabled.
Any ideas?
I also tried creating an hidden input field that gets updated everytime the select value gets updated - but still it is noto working .
My sample form (pls ignore any typos since i stripped of most of the code. The functionality works just fine. it is just the disabling of button that doesnt work)
<form name="customizeForm" id="customize-form" class="bm-form" data-ng-cloak novalidate data-ng-submit="ctrl.saveCustomization(customizeForm.$valid)">
<!--if i change this input, it works -->
<input id="answer" type="text" name="answer" data-ng-model="ctrl.answer">
<!--If i change the below dropdown, it doesnt work and the button is still disabled -->
<div class="form-group dropdown col-xs-12 col-md-6" data-uib-dropdown data-keyboard-nav data-is-open="status[$index].isopen" data-ng-init="status[$index].newSelectedValue = ''">
<button id="profile-menu" type="button" class="form-control select-control dropdown-togglebtn" data-uib-dropdown-toggle>
<span class="selected" data-ng-bind-html="status[$index].newSelectedValue</span>
<span class="icon icon-down-arrow" aria-hidden="true"></span>
</button>
<ul class="dropdown-menu" role="menu" data-aria-labelledby="menu">
<li data-ng-repeat="answer in question.Answers">
{{answer.AnswerDesc}}
</li>
</ul>
</div>
<div id="save-profile" class="text-center form-submit">
<button type="submit" data-ng-disabled="!customizeForm.$dirty" id="btn-profile-questionnaire" class="btn btn-card reverse" title="Save">
Save</span>
</button>
</div>
</form>
I'm new to angular so bear with me. I have a form with a dropdown, textbox and a button. The user has to select an option from the dropbox and enter a value in the textbox before the form becomes valid.
<form name='personDataSourceForm' novalidate ng-submit='personDataSourceForm.$valid && PersonCtrl.SaveDataItem()'>
<span>Invalid: {{personDataSourceForm.$invalid}}</span><br />
<span>valid: {{personDataSourceForm.$valid}}</span>
<div class="input-group">
<div class="input-group-addon">
<select class="form-control input-sm" required ng-model='PersonCtrl.sp.person.newItem.dataType' ng-options='opt as opt.text group by opt.dataType for opt in PersonCtrl.DataItemTypes'>
<option value="" disabled selected>Choose...</option>
</select>
</div>
<input type="text" class="form-control input-sm" ng-model='PersonCtrl.sp.person.newItem.value' required>
<div class="input-group-btn">
<button class="btn btn-default btn-sm" ng-class="{ 'btn-success' : PersonCtrl.sp.person.newItem.dataType.dataType && PersonCtrl.sp.person.newItem.value }" type="submit">Save</button>
<button class="btn btn-link btn-sm" type="button" ng-click="PersonCtrl.StopAddItem()">Cancel</button></div>
</div>
</form>
I quickly added 2 spans to show the validation state. When both are empty the form shows invalid which makes sense.
As soon as I type in a value in the textbox then suddenly the form is valid even though the dropdown still hasn't been changed.
Why is my dropdown not getting validated? I've even tried this solution AngularJS Dropdown required validation
My initial thought is that you already have that default value selected:
<option value="" selected>Choose...</option>
so it does technically have a value of "", which is fulfilling the required.
I think you will need to look at PersonCtrl.sp.person.newItem. The form becomes valid when both the dataType and value get solid. My guess is the item always has its dataType solid and valid so when the new value is entered the whole form becomes valid.
Why don't your select ad input have a name attribute? The name attribute is necessary for form validations to work properly.
I think form creates a map of name->validity for each input component and it could be that you have omitted it they both (select and input) map to the same validity object. If this is the case, then anyone becomes valid, effectively makes the status of the other one valid as well and hence they are both valid the form becomes valid.
Please add separate names for them and see if the problem is resolved. My opinion above is a strong guess and I have not dived into Angular code to check ng-form's behaviour.
I am trying to make a search function which works if I put in the query params into my URL directly but I don't know how to make it work so that it picks it up from the search box and executes it. I have used ng-model to map the text itself to the controller which works but the execution isn't working.
The navbar form:
<form ng-submit="doSearch()" class="navbar-form">
<div class="form-group" style="display:inline;">
<div class="col-md-offset-4 input-group" style="display:table;">
<input ng-model="search.text" class="form-control" name="search" placeholder="Search Here" autocomplete="off" autofocus="autofocus" type="text">
<span class="input-group-addon" style="width:1%;">
<span class="glyphicon glyphicon-search"></span>
</span>
</div>
</div>
By the way, my doSearch() function works just fine when I run it manually and so is the search itself. I have also validated that search.text comes through. I guess what I am asking is how do I make the icon (glyphicon-search) execute ng-submit="doSearch()" when the user clicks on it or presses enter.
Sorry if this is very obvious. I was always more on the backend side of things so am sorta new to HTML and Angular.
Thanks
You could place the icon inside a <button> element instead of <span>, tweak a bit of css to integrate it to the form field.
In regards to trigger search on enter, with jQuery something like this could be used:
$('input').keypress(function (e) {
var key = e.which;
if(key == 13) // the enter key code
{
doSearch();
}
});
did you try using <button type="submit"> before your search icon
<span class="glyphicon glyphicon-search"></span>
to specify that clicking on that button is equivalent to a submit event for that form.
So this worked in the end. First, the proper HTML which works:
<form ng-submit="doSearch()" class="navbar-form">
<div class="form-group" style="display:inline;">
<div class="col-md-offset-4 input-group" style="display:table;">
<input ng-model="search.text" class="form-control" name="search" placeholder="Search Here" autocomplete="off" autofocus="autofocus" type="text">
<span ng-click="doSearch()" class="input-group-addon" style="width:1%;">
<span class="glyphicon glyphicon-search"></span>
</span>
</div>
</div>
</form>
Furthermore, there was an issue with the view not connecting to the controller. Actually, let me rephrase that - it was connecting to the controller but only when the whole page loaded and for my test, I had a console.log('I have loaded') put in there. So when I saw "I have loaded", I thought my controller was invoked properly.
However, the doSearch() was in the controller which was connecting via angular routing, so the ng-View was not connecting to the right controller.
I am not sure if this means anything to anyone but I am writing this in case someone else comes across an issue like mine.
So just to summarise the issue was not with the HTML as I originally thought. ng-submit (for form submission when pressing enter) and ng-click (for clicking the glyphicon) does the trick.
I'm building a small search app using Elasticsearch and AngularJS. I'm using AngularJS UI bootstrap typeahead to implement autocomplete and I'm using ES's edge_n_grams and highlight object to 1) generate the suggestions and 2) highlight the suggestions, respectively. ES highlight object wraps the suggestions in HTML <em></em> tags... which seems to be causing some issues with how I have things setup.
1) When I press Enter key instead of clicking on the search button - all that happens is the search terms are displayed wrapped in the <em></em> tags AND no search is performed... <em>search terms</em>
2) When I select a suggestion with the mouse, same thing happens.
The only time search performs is when I type a query in and click the search button...
Here is the search form that I'm using, I have ng-submit="search()" on the form element and on the button, not sure where I'm going wrong......?
<form name="q" ng-submit="search()" class="navbar-form" id="results-search" role="search">
<div class="input-group">
<input type="text" name="q" ng-model="searchTerms" class="form-control input-md" placeholder="{{ searchTerms }}" id="search-input" uib-typeahead="query for query in getSuggestions($viewValue)" typeahead-on-select="search($item)">
<div class="input-group-btn">
<button type="submit" ng-submit="search()" class="btn btn-primary btn-md"><i class="fa fa-search fa-lg"></i></button>
</div>
</div>
</form>
Am I doing something wrong with the UI Bootstrap Typeahead?
More clarification
So basically what I'm asking is how do I get the tags stripped from the suggestions, on selection and for searching?
Similar kind of example already asked in Stackoverflow: Click here
I am working with AngularUI Datepicker.I have seprate partial views each having ng-repeat .There I am using AngularUI-Bootstrap-Datepickers and it is making page load really slow.
I followed this answer:
Many UI-Bootstrap-Datepickers on page loads very slowly - can I use a single instance and move element?
But I got few other issues.In this approach we are using separate ng-if to switch from span to textbox. But switching between them is taking considerable amount of time which make it visible to user that we are playing with textboxes.(check Image
http://i.stack.imgur.com/YxZXQ.png )
I also followed this : https://github.com/angular-ui/bootstrap/pull/3666/commits
But I am unable to integrate the changes and successfully run the datepicker.
Is there any reliable solution to this issue?
Many UI-Bootstrap-Datepickers on page loads very slowly - can I use a single instance and move element?
<p class="input-group">
<span class="form-control" ng-if="!date.opened1">{{date.data1|date:format}}</span>
<input type="text" class="form-control"
ng-if="date.opened1" datepicker-popup="{{format}}" ng-model="date.data1"
is-open="date.opened1"
datepicker-options="dateOptions"
close-text="Close"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, date,1)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
code
$scope.open = function($event,date,i) {
$event.preventDefault();
$event.stopPropagation();
date['opened'+i] = !date['opened'+i];
};
Plunkr link