I'm trying to write autocomplete in Angularjs. It works for me except the click on the suggestion. From the console log it looks like whenever I click on the suggestion, ng-blur of the input element is called as it input element loses focus and ng-click is never called. Can anybody suggest a solution here?
Here is my code.
<!DOCTYPE html>
<head>
<title>Autocomplete</title>
<style>.wrapper {display: none;}.wrapper ul {list-style-type: none;}.wrapper li {padding: 5px;line-height: 25px;cursor: pointer;}</style>
<!-- Angular JS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.5/angular.min.js"></script>
</head>
<body ng-app="MyApp">
<div ng-controller="SuggestionCtrl">
<form action="/index.html">
<input type="search" name="q" autocomplete="off"
ng-model="q"
ng-focus="showSuggesions()"
ng-blur="hideSuggesions()"
ng-change="getSuggestion()">
<div class="wrapper"
ng-if="hasSuggestions"
ng-style="suggestionStyle">
<ul>
<li ng-repeat="suggestion in suggestions"
ng-click="search(suggestion)">
{{suggestion}}
</li>
</ul>
</div>
</form>
</div>
var app = angular.module("MyApp", []);
app.controller("SuggestionCtrl", function ($scope) {
$scope.suggestions = ["India", "United States", "England", "Australia"];
$scope.showSuggesions = function () {
$scope.suggestionStyle = { display: "block", 'background-color': '#ddd' };
};
$scope.hideSuggesions = function () {
$scope.suggestionsVisible = false;
$scope.suggestionStyle = { display: "none" };
console.log('hideSuggestions called');
};
$scope.hasSuggestions = function(){
return $scope.suggestions.length > 0;
}
$scope.getSuggestion = function () {
// get suggestions from api
};
$scope.search = function (suggestion) {
window.location = window.location + "?q=" + suggestion;
};
});
The click event executes after blur - list with suggestions hides before you are able to click it. The simple solution is to use mousedown instead of click
<input type="search" name="q" autocomplete="off"
ng-model="q"
ng-focus="show=true"
ng-blur="show=false">
<div class="wrapper"
ng-style="suggestionStyle">
<ul ng-show="show">
<li ng-repeat="suggestion in suggestions">
<a ng-mousedown="search(suggestion)">{{suggestion}}</a>
</li>
</ul>
plunker: http://plnkr.co/edit/Y4e4dYD4qJZwnNRmgWiN?p=preview
Related
I have HTML code with inline element:
<span class="title" ng-click="update()">Rock</span>
How to replace this element on input element after click for edit?
And then after push enter on input return back span element?
I tried with directives ng-hide(), ng-show(). But I wonder
You can use either
<span class="title" ng-hide="isEdited" ng-click="update()">Rock</span>
or
<span class="title" ng-show="!isEdited" ng-click="update()">Rock</span>
or even
<span class="title" ng-if="!isEdited" ng-click="update()">Rock</span>
In any case you will want to reference something that can be truthy. For example in your controller you would have something like this in your function
/*the init function just makes sure that everything is setup
and nothing caries over from any local storage or anything
else you may be using*/
init();
init function(){
$scope.isEdited = false;
}
$scope.update = function(){
$scope.isEdited = true;
}
What you need to do is set a variable that contains the state;
<html>
<body ng-app="app">
<div ng-controller="mainController as $ctrl">
<span ng-if="!$ctrl.isInEditMode" class="title" ng-click="$ctrl.update()" ng-bind="$ctrl.spanText"></span>
<div ng-if="$ctrl.isInEditMode">
<input type="text" placeholder="Value for rock" ng-model="$ctrl.spanText" />
<button ng-click="$ctrl.update()">Done</button>
</div>
</body>
</html>
angular.module('app', [])
.controller('mainController', function($scope) {
this.isInEditMode = false;
this.spanText = 'Rock';
this.update = (function() {
this.isInEditMode = !this.isInEditMode;
}).bind(this);
});
I have prepared a Codepen that shows an possible solution: http://codepen.io/stefferd/pen/QdQrrv
If I have for example a simple todo list:
HTML
<ul ng-repeat="todos in keyVar.list">
<li ng-class="{ 'completed' : keyVar.toggle }">
{{ todos }}
<input ng-if="!keyVar.toggle" type = "checkbox" ng-click="keyVar.toggle=true" >
<input ng-if="keyVar.toggle" type = "checkbox" checked= "true" ng-click="keyVar.toggle=false" ></input>
</li>
</ul>
JS
angular.module("todoApp", [])
.controller("mainCtrl", function(){
var keyVar = this;
keyVar.title ="Angular Todos";
keyVar.list=[];
keyVar.toggle = false;
keyVar.todosArr = function(){
keyVar.list.push(keyVar.todo)
keyVar.todo = "";
}
});
When I run this, I can add a todo, and check and uncheck the checkbox which toggles a class of completed, but it gives the class to every todo and if I check one checkbox, all of them go checked. I think I have to use something like keyVar.list[$index]? But I'm not sure where to use it or how.
Try like this. I define for each todo a status. and bind that to checkbox. when user click on checkbox change it.
angular.module("todoApp", [])
.controller("mainCtrl", function(){
var keyVar = this;
keyVar.title ="Angular Todos";
keyVar.list=[
{
"title":"Todo1",
"status":false
},
{
"title":"Todo2",
"status":false
}
];
keyVar.todosArr = function(){
keyVar.list.push({title:keyVar.todo,status:false})
keyVar.todo = "";
}
});
.completed{
text-decoration: line-through;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="todoApp" ng-controller="mainCtrl as keyVar" class="container">
<input type="text" ng-model="keyVar.todo">
<button ng-click="keyVar.todosArr()">Add Todo</button>
<ul ng-repeat="todos in keyVar.list">
<li ng-class="{ 'completed' : todos.status }">
{{ todos.title }}
<input ng-model="todos.status" type = "checkbox" ng-click="keyVar.toggle=true" >
</li>
</ul>
</div>
Try use ng-checked instead of ng-click.
<input ng-if="!keyVar.toggle" ng-checked="keyVar.toggle=true">
I am trying to render a page using ng-view in that I am using ng-repeat to render my radio buttons and the ng-model which is there not updating my value in controller..
MY HTML
<div ng-repeat="role in Roles">
<input type="radio" ng-model="Role"
value="role" ng-value="role"
name="Roles"
id={{role}}>
<span>{{role}}</span>
</div>
MY CONTROLLER
console.log("Moving Forward--"+$scope.Role);
on console printing undefined..
Your code works fine for me, however you can set an object on the $scope to set your properties which you get when the user interacts as a single data source which will be same when updated from different controllers/sources.
Works fine like the way you do check below example
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
DefaultController.$inject = ['$scope'];
function DefaultController($scope) {
$scope.availableRoles = ['Admin', 'Manager', 'User'];
$scope.logSelectedRole = logSelectedRole;
function logSelectedRole() {
console.clear();
console.log("Moving Forward -- " + $scope.selectedRole);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController">
<div ng-repeat="role in availableRoles">
<input type="radio" ng-model="$parent.selectedRole" value="role" ng-value="role" name="Roles" id="{{role}}"/> <span style="display: inline-block; line-height: 28px;">{{role}}</span>
</div>
<button ng-click="logSelectedRole()">Log to console</button>
</div>
</div>
Same example using controller aliasing
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.availableRoles = ['Admin', 'Manager', 'User'];
vm.logSelectedRole = logSelectedRole;
function logSelectedRole() {
console.clear();
console.log("Moving Forward -- " + vm.selectedRole);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<div ng-repeat="role in ctrl.availableRoles">
<input type="radio" ng-model="ctrl.selectedRole" value="role" ng-value="role" name="Roles" id="{{role}}"/> <span style="display: inline-block; line-height: 28px;">{{role}}</span>
</div>
<button ng-click="ctrl.logSelectedRole()">Log to console</button>
</div>
</div>
Check this video and the below example about the difference when you create an object on the $scope and assign your properties on them instead of assigning directly. I recommend you to use the below approach instead of using $parent.something or use controller aliasing syntax.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
DefaultController.$inject = ['$scope'];
function DefaultController($scope) {
$scope.data = {
selectedRole: undefined
};
$scope.availableRoles = ['Admin', 'Manager', 'User'];
$scope.logSelectedRole = logSelectedRole;
function logSelectedRole() {
console.clear();
console.log("Moving Forward -- " + $scope.data.selectedRole);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController">
<div ng-repeat="role in availableRoles">
<input type="radio" ng-model="data.selectedRole" value="role" ng-value="role" name="Roles" id="{{role}}"/> <span style="display: inline-block; line-height: 28px;">{{role}}</span>
</div>
<button ng-click="logSelectedRole()">Log to console</button>
</div>
</div>
<div ng-repeat="role in Roles">
<input type="radio" data-ng-model="Role"
data-ng-value="role"
ng-change="Value()"
name="Roles">
<span>{{role}}</span>
</div>
In controller
$scope.Value=function(){
console.log("Moving Forward--"+$scope.Role);
}
Working fine...
I have a problem to show INPUT field when do some action.
I have BUTTON (Click here) as soon as user made a click event on button i wanted to show input field
I have done this by using jQuery.
Can any one help me in Angular.js
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.boxShow = false;
});
</script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
show box
<div ng-show="boxShow">
<textarea rows="4" cols="50">text</textarea>
</div>
</div>
</div>
https://jsfiddle.net/bxwjpmaa/1/
HTML
<div class="btn btn-primary" ng-click="openTextBox();">Click Me To open text box</div>
<div ng-show="openTextBox == true">
<input type="text"/>
</div>
SCRIPT :
$scope.openTextBox = function () {
$scope.openTextBox = true;
}
please don't take scope variables and function names same
example here
$scope.openTextBox = function () {
$scope.openTextBox = true;
}
//this is not correct as per angular documentation because scope.openTextBox name already assigned to scope function,again its assigning scope variable "$scope.openTextBox = true" here u will get errors when ever u clicked div second time" TypeError: boolean is not a function" it will throw this error.so please dont use which is already assigned scope function dont assign scope variable
see this fiddle url : https://jsfiddle.net/veerendrakumarfiddle/bxwjpmaa/2/
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ol>
<li ng-repeat="element in elements">
<input type="text" ng-model="element.value"/>
</li>
</ol>
<br/>
<b>Click here to add Textbox:</b><br/><input type="button" value="New Item" ng-click="newItem()"/>
<br/>
<br/>
<b>Click here to see ng-model value:</b><br/>
<input type="button" value="submit" ng-click="show(elements)">
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
var counter=0;
$scope.elements = [ {id:counter, value : ''} ];
$scope.newItem = function(){
counter++;
$scope.elements.push( { id:counter,value:''} );
}
$scope.show=function(elements)
{
alert(JSON.stringify(elements));
}
});
</script>
</body>
</html>
I'm trying to build a media library in which only one image can be selected at a time. To do this, I have a list generated with AngularJS's ng-repeat function. So far, when I click on an element, it adds a highlighting class to a child div and toggles the visibility of a child form element. How can I make the click do the opposite for every other element in the ng-repeat?
<li ng-click="show=!show" ng-repeat="media in media">
<div ng-if="show" class="selected">
<input class="bulk-check" type="hidden" name="ids[]" value="#include('_helpers.media_id')">
</div>
</li>
You could just save displayed media in a temp variable in your controller and have 2 functions 1) set the media object on click of item 2) can show function which checks for object equality.
Controller:
var shownMedia = $scope.medias[0]; //Set you default media
$scope.selectMedia = function(media) {
shownMedia = media; //on click, set the new media as selected media
}
$scope.canShow = function(media) {
return angular.equals(shownMedia, media); //Check if this is the displayed media
}
View:
<li ng-click="selectMedia(media)" ng-repeat="media in medias">
{{media.name}}
<div ng-if="canShow(media)" ng-class="{selected : canShow(media)}">
{{media.description}}
<input class="bulk-check" type="hidden" name="ids[]" value="#include('_helpers.media_id')">
</div>
</li>
Example implementation Demo
angular.module('app', []).controller('ctrl', function($scope) {
$scope.medias = [{
name: 'media1',
description: "media1"
}, {
name: 'media2',
description: "media2"
}, {
name: 'media3',
description: "media3"
}];
var shownMedia = $scope.medias[0];
$scope.selectMedia = function(media) {
shownMedia = media;
}
$scope.canShow = function(media) {
return angular.equals(shownMedia, media);
}
});
.selected{
color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<ul>
<li ng-click="selectMedia(media)" ng-repeat="media in medias">
<span ng-class="{selected : canShow(media)}">{{media.name}}</span>
<div ng-if="canShow(media)">
{{media.description}}
<input class="bulk-check" type="hidden" name="ids[]" value="#include('_helpers.media_id')">
</div>
</li>
</ul>
</div>
This should work
<li ng-repeat="media in mediaList" ng-click="media.show=!media.show" >
<div ng-if="media.show" class="selected">
<input class="bulk-check" type="hidden" name="ids[]" value="#include('_helpers.media_id')">
</div>
</li>