angular ng-focus / focus input element - angularjs

I have three input elements styled as buttons. On ng-keyup I invoke a function in my controller.
Now the problem is I have to manually click on one of them to get a focus, only then keyUp works.
I tried ng-focus='focus' and then setting $scope.focus=true in controller, it didn't work.
<div class="row startButtonRow">
<div class="col col-50" align="center">
<button class="button button-dark startButton" ng-click="start()" ng-disabled="disableStart">Start</button>
</div>
<div class="col" align="center">
<input ng-focus="focus" type="button" class="button button-dark startButton" ng-disabled="disableStop" ng-keyup="stopTimer($event)">
</div>
<div class="col" align="center">
<input type="button" class="button button-dark startButton" ng-disabled="disableStop" ng-keyup="stopTimer($event)">
</div>
<div class="col" align="center">
<input type="button" class="button button-dark startButton" ng-disabled="disableStop" ng-keyup="stopTimer($event)">
</div>
</div>
Once I click Start button the symbols start appearing on three columns and I am supposed to press corresponding button (here input element with key-up) as soon a specific symbol appear. I don't want to click on the element first and then being able to use keyboard keys.

ng-keyup does not have to go on one of your input elements, you could move it to your body element, or whatever your ng-app element is, and it will still catch keypresses.
On a different note, I believe you are misunderstanding what ng-focus does. It evaluates the given expression when the input is focused, it is not telling your browser to focus that element. You will want to build a custom directive to focus your inputs, see How to set focus on input field?
You could add something like this to your controller:
var handler = function(e){
if (e.keyCode === 37) {
// left arrow
} else if (e.keyCode === 38) {
// up arrow
} else if (e.keyCode === 39) {
// right arrow
}
};
var $doc = angular.element(document);
$doc.on('keyup', handler);
$scope.$on('$destroy',function(){
$doc.off('keyup', handler);
})

Related

AngularJS give active class to button in button group

I have a button group with some buttons, two created with html and others are created with a ng-repeat. I want that on click the button have an active class so I can custom it to show it's activated.
So here is what I do :
<div class="btn-group" role="group" aria-label="Basic example"
ng-init="selectedTab = 'raw'">
<button class="btn"
ng-click="selectView('raw'); selectedTab = 'raw'; console.log(selectedTab);"
ng-class="{'active':selectedTab === 'raw'}">Raw data
</button>
<button class="btn"
ng-click="selectView('summary'); selectedTab = 'summary'; console.log(selectedTab);"
ng-class="{'active':selectedTab === 'summary'}">Summary
</button>
<button class="btn" ng-repeat="(key, value) in views"
ng-click="selectView(key); selectedTab = key; console.log(selectedTab);"
ng-class="{'active':selectedTab === key}">
{{ key }}
</button>
</div>
My problem is that for the two first one all works fine, when I click on the first button the class active is added, and when I click on the second the class is removed from the first one and added to the second one.
The problem is about the buttons generated by the ng-repeat, when I click on them it's add the active class to the button but when I click on another button it's not removing the class, so they can all have the activate class.
What am I doing wrong ?
Remember that ng-repeat creates its own local scope so any variables you reference there that are not defined on the parent scope will be created locally. Although you can put multiple commands in ng-click it is discouraged - it also seems that doing so will not cause a digest cycle for those items inside the ng-repeat.
You can resolve all of this by making selectedTab a property on your controller and having the selectView method set the value of selectedTab. Here's a quick example:
angular.module('app', [])
.controller('ctrl', ($scope) => {
$scope.selectedTab = 'raw';
$scope.views = {
Detail1: 'details',
Detail2: 'details',
Detail3: 'details'
};
$scope.selectView = function(view) {
$scope.selectedTab = view;
}
});
.active {
color: red !important;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="btn-group"
role="group"
aria-label="Basic example">
<button class="btn"
ng-click="selectView('raw')"
ng-class="{'active':selectedTab === 'raw'}">Raw data</button>
<button class="btn"
ng-click="selectView('summary')"
ng-class="{'active':selectedTab === 'summary'}">Summary</button>
<button class="btn"
ng-repeat="(key, value) in views"
ng-click="selectView(key)"
ng-class="{'active':selectedTab === key}">
{{ key }}
</button>
</div>
</div>
New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view, ng-include and ng-if all create new child scopes, so the problem often shows up when these directives are involved.
The assignment selectedTab = key is being done on the child scope created by the ng-repeat directive. The solution is to do the assignment to a property of an object:
<div class="btn-group" role="group" aria-label="Basic example"
ng-init="selected = {tab:'raw'}">
<button class="btn"
ng-click="selectView('raw'); selected.tab = 'raw';"
ng-class="{'active':selected.tab === 'raw'}">Raw data
</button>
<button class="btn"
ng-click="selectView('summary'); selected.tab = 'summary';"
ng-class="{'active':selected.tab === 'summary'}">Summary
</button>
<button class="btn" ng-repeat="(key, value) in views"
ng-click="selectView(key); selected.tab = key;"
ng-class="{'active':selected.tab === key}">
{{ key }}
</button>
</div>
For more information, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

Angular Material swipe gesture works hardly

I am trying to add swipe functionality to a ng-repeated list of elements. However, the swiping works badly. Sometimes a swipe gestures (all on desktop) is recognized, but most of the times I'm click and swiping like a madman to achieve the expected result.
I am using Material Angular.
Code:
<div ng-repeat="link in Links | filter: { category: 'quick' }">
<div ng-show="!link.show" md-swipe-left="link.show = true">
<div class="lv-item ">
<span href="{{link.url}}" class="no-select" target="_blank" >
<div class="lv-title" class="no-select">{{link.title}}</div>
<small class="lv-small" class="no-select">{{link.description}}</small>
</span>
</div>
</div>
<div ng-show="link.show" md-swipe-right="link.show = false">
<div class="lv-item delete" >
<button ng-click="deleteLink(link.id)">Verwijder</button>
</div>
</div>
</div>
On the Angular Material swipe docpage (https://material.angularjs.org/latest/demo/swipe) it seems easy and it works like a charm. However my implementation of the directive doesn't seem to work as it should. It rather lets me select the text inside the element than swiping.
Also, I'd rather want the span to be a a href, but this only lets me drag the whole element out of space.
I believe that to assure a proper work of all material function you should use their containers and directives instead. So you should put all of that inside a md-content, and also use ng-ifs instead of ng-show on the swiped div. Which would result in something like that :
<md-content>
<div ng-repeat="link in Links | filter: { category: 'quick' }">
<div ng-if="!link.show" md-swipe-left="link.show = true">
<div class="lv-item ">
<span href="{{link.url}}" class="no-select" target="_blank" >
<div class="lv-title" class="no-select">{{link.title}}</div>
<small class="lv-small" class="no-select">{{link.description}}</small>
</span>
</div>
</div>
<div ng-if="link.show" md-swipe-right="link.show = false">
<div class="lv-item delete" >
<button ng-click="deleteLink(link.id)">Verwijder</button>
</div>
</div>
</div>
</md-content>
I used this kind of code snippet on some md-sidenav and it works. By the way, if you're using chrome and use mobile view, the md-swipe-left is always triggered, doesn't matter if you swipe left, right, top or bottom.
Hope this helps

hide div while clicking on outside it in angularjs

I am trying to hide a div when i clicked on outside it, below is my div
<div ng-show="item.showLimit" class="set-limit">
<input type="text" ng-model="item.newConcLimit" />
<div>
<button type="button" ng-click="item.newConcLimit = 0;">No Limit</button>
<button ng-disabled="!(item.newConcLimit >= 0)" type="button" ng-click="setConcLimit(item);">OK</button>
</div>
</div>
in controller I'm trying to set item.showLimit = false in window click function but it is not setting.
Try this out.
$(window).click(function(e){
$scope.item.showLimit = false;
});
Make sure you are adding this too. Otherwise the div will hide if you click inside the division also.
$('.set-limit').click(function(e){
e.stopPropagation();
});

ion-content won't resize when keyboard appears

I have an application with a chat functionality which works great, except for one part, when the keyboard appears, the ion-content won't resize to a proper height, so I am stuck when I want to scroll to the top and the header disappears completely. The view has a header, content and footer and what I want is the footer to appear above the keyboard and the content to resize so it fits between the header and the footer-bar. The view I have created is as followed:
<ion-view id="userMessagesView" cache-view="true" flow-init flow-name="imageTemp.imageTemp" ng-if="!inChatSettings">
<div class="loader-center" ng-if="!doneLoading">
<div class="loader">
<i class="icon ion-loading-c"></i>
</div>
</div>
<div class="loader-center" ng-if="errorLoading">
<div class="loader">{{'error_loading_messages'|translate}}</div>
</div>
<ion-content class="has-header has-footer" has-bouncing="true" delegate-handle="userMessageScroll" style="background:red;">
<ion-refresher pulling-text="{{'pull_load_earlier'|translate}}" on-refresh="loadMore()"></ion-refresher>
<div ng-repeat="message in messageThread.messages | orderBy : 'postDate'" class="message-wrapper">
<div class="chat-bubble" ng-class="{ false: 'left', true:'right'}[{{message.postedBy|isCurrentUser}}]">
<div class="message-detail">
<span class="bold">{{message.postedBy.name}}</span>
</div>
<div class="message" ng-bind-html="message.message | nl2br" autolinker></div>
<img ng-src="{{message.imageUrl}}" ng-if="message.imageUrl"/>
<small am-time-ago="message.postDate">{{message.postDate|timeago}}</small>
</div>
<div class="cf"></div>
</div>
</ion-content>
<ion-footer-bar class="bar-light message-footer">
<button class="button button-icon icon icon-upload" flow-btn flow-file-added="imageUploaded($file)" flow-name="imageTemp.imageUrlTemp"></button>
<label class="item-input-wrapper" for="newmessage">
<textarea focus-me="input.focusInput" id="newmessage" ng-model="input.message" value="" required minlength="1" maxlength="1500" msd-elastic></textarea>
</label>
<button class="button button-clear" type="submit" ng-disabled="!input.message || input.message === ''" ng-click="sendMessage()" translate="send"></button>
</ion-footer-bar>
</ion-view>
I tried adding the keyboard-attach attribute to the ion-footer-bar, but the footer only gets bigger when I add this. Plus the footer already stays on top of the keyboard, so it appears unneeded. I have the following situation, it also appears that when I type something, the view goes up a little more.
This is when the keyboard is shown:
This is when the keyboard is hidden:
Does any of you know how to resize the ion-content to a normal height when the keyboard appears?
I have tried some things and the problem seemed to disappear, yet I don't think the solution is the right one or if this is actually the thing what solved the issue. So if anyone got a better solution, please share. First thing I had to do was including the Ionic keyboard plugin to get events based on the keyboard.
Inside the CSS, I have added:
.message-footer { min-height: 44px; }
Inside my controller I added the following code:
$scope.$on('taResize', function (e, ta) {
if(!ta || !footerBar) return;
var taHeight = ta[0].offsetHeight + 10;
var newHeight = (taHeight < 44) ? 44 : taHeight;
scroller.style.bottom = newHeight + 'px';
footerBar.style.height = newHeight + 'px';
});

Angular Bootstrap UI: Input Fields in Tab-Heading

Again I got a Problem with Angular Bootstrap UI Tabs.
Short description of my problem:
I want the user to create different pages with different titles. After a page is created, I create a new tab with the pagetitle and user can add content. That works fine so far.
Now, in the uib-tab-heading I have an option to edit the page-title
<uib-tab-heading>
<div class="pull-left">
<span data-ng-if="!editable[$index]">{{title}}</span>
<input data-ng-if="editable[$index]" data-ng-model="titles[$index]">
</div>
<div class="pull-right">
<button data-ng-if="!editable[$index]" data-ng-click="edit($index)"><span class="glyphicon glyphicon-wrench"></span></button>
<button data-ng-if="editable[$index]" data-ng-click="save($index)"><span style="color:green;" class="glyphicon glyphicon-ok"></span></button>
</div>
<div style="clear:both;"></div>
</uib-tab-heading>
The button action sets a variable so the input field in the tab appears. That works so far.
But in the input field I only can edit one single letter, then, after input, the input field looses its focus and the tab is changed in a random way.
Is there a common method to disable keyboard interaction with the tabs so I can change the value of the input field without getting the tab changed?
One option is just to force the focus back to the input element whenever it is modified.
See fiddle: https://jsfiddle.net/masa671/2mq3106a/
Markup:
<input data-ng-if="editable[$index]" ng-model="titles[$index]" focus-me>
JavaScript:
.directive('focusMe', function () {
return {
require: 'ngModel',
link: function (scope, elem, attr, ngModel) {
scope.$watch(function () {
return ngModel.$modelValue;
}, function() {
elem[0].focus();
});
}
};
});
Thanks for your answer!
I modified your fiddle a bit to fit my code.
See fiddle: https://jsfiddle.net/2mq3106a/7/
<div ng-controller="MyCtrl">
<uib-tabset>
<uib-tab class="tabcontent-bordered" data-ng-repeat="pageTitle in titles">
<uib-tab-heading>
<div class="pull-left">
<span data-ng-if="!editable[$index]">{{pageTitle}}</span>
<input id="$index" data-ng-if="editable[$index]" ng-model="titles[$index]" focus-me>
</div>
<div class="pull-right">
<button data-ng-if="!editable[$index]" data-ng-click="edit($index)"><span class="glyphicon glyphicon-wrench"></span></button>
<button data-ng-if="editable[$index]" data-ng-click="save($index)"><span style="color:green;" class="glyphicon glyphicon-ok"></span></button>
</div>
<div style="clear:both;"></div>
</uib-tab-heading>
I am on Tab {{$index}}
</uib-tab>
</uib-tabset>
</div>
I do not lose the focus on the input field, thats works so far, but there is still an other problem.
As you may can see in the fiddle if i change input value of the input field, the other tab gets active state and so the content of the other tab is shown.

Resources