-
Notifications
You must be signed in to change notification settings - Fork 24
Ionic Elastic Textarea
At the moment that I'm writing this, ionic2 framework's component called ion-textarea
doesn't have a pretty basic functionality to grow in height automatically as new lines are added to it. In this section we are going to write our own wrapper component around the ion-textarea
that will give it this functionality.
There's on old post in ionic version 1 forum that's called Ionic Elastichat - Chat Demo w/ Auto Resizing Textarea that served as an inspiration to my custom elastic-textarea
component.
I'd also like to mention Bastian, who helped to push me in the right direction with his ionic 1 directive in typescript-version that he posted as an answer to my forum question.
Below you can see the full implementation of my elastic-textarea
component. I added it to app/pages/components/elasticTextarea.js in my project. Checkout the code and then we'll go through interesting bits.
import {Component, ViewChild} from '@angular/core';
@Component({
selector: 'elastic-textarea',
inputs: ['placeholder', 'lineHeight'],
template:
`
<ion-textarea #ionTxtArea
placeholder='{{placeholder}}'
[(ngModel)]="content"
(ngModelChange)='onChange($event)'></ion-textarea>
`,
queries: {
ionTxtArea: new ViewChild('ionTxtArea')
}
})
export class ElasticTextarea {
constructor() {
this.content = "";
this.lineHeight = "22px";
}
ngAfterViewInit(){
this.txtArea = this.ionTxtArea._elementRef.nativeElement.children[0];
this.txtArea.style.height = this.lineHeight + "px";
}
onChange(newValue){
this.txtArea.style.height = this.lineHeight + "px";
this.txtArea.style.height = this.txtArea.scrollHeight + "px";
}
clearInput(){
this.content = "";
this.txtArea.style.height = this.lineHeight + "px";
}
setFocus(){
this.ionTxtArea.setFocus()
}
}
I wanted to reuse the ion-textarea
functionality as much as possible, and only extend it by making it resize automatically. Because of this I decided to wrap the ion-textarea
inside my directive.
I'm using a two way binding for my ngModel
, and I'm binding it to content
property. This basically means that if I change the text of my ion-textarea
, the content
property will get updated, and vice versa.
I've also attached an ngModelChanged
event listener, that gets triggered every time the model of ion-textarea
changes, which basically means any time its text is updated. The $event
that I'm passing to the onChange(..)
method will actually be the new text value inside the ion-textarea
, however, I won't be using this information at the moment.
Before I continue, I want to point out that with this.ionTxtArea._elementRef.nativeElement.children[0]
I'm obtaining the native HTML textarea
input element that will get generated inside the ion-textarea
once the angular resolves our code. ion-textarea
is basically only extending the textarea
with additional styling and event handling, similarly to what I'm doing by wrapping the ion-textarea
in my elastic-textarea
. This is a dirty way to obtain this textarea
element, but I don't know any alternative approach.
Moving on, the onChange(..)
method, which gets triggered on ngModelChanged
event, will handle the automatic resizing of the nested textarea
, which will also resize the ion-textarea
. The logic behind the automatic resize is quite simple. Firstly, I'm setting the height of textarea
to the height of the single line of text. At this point, the framework will automatically calculate the required scrollHeight
that is required to scroll through all the lines of text inside the textarea
element. Then, I'm simply using this calculated scrollHeight
and I'm just setting the height of the element to this height.
That's it, those are the key parts of my elastic-textarea
component. It can be used in code like this:
<elastic-textarea placeholder="Type to compose" lineHeight="22"></elastic-textarea>
You've probably noticed the inputs
property that I'm setting in my component's decorator. These are Angular2 properties and there are two types of them: @Input
and @Output
. In ionic2 framework, they are marked simply as inputs
, and outputs
inside the decorator, and then the names of these bindable properties are added to the array.
- @Input - Declares a data-bound input property. Angular automatically updates data-bound properties during change detection.
- @Output - Declares an event-bound output property. When an output property emits an event, an event handler attached to that event is invoked.
I'm using the inputs
to mark the placeholder
and lineHeight
as the input properties, and then I'm using them inside my component. You can see how I'm using these properties with my component:
<elastic-textarea
placeholder
="Type to compose"
lineHeight
="22"></elastic-textarea>
The aliasing of the properties is also available. For example, if I declared the inputs as: inputs: ['msg: message']
. This would mean that inside my component I would use the variable called msg
, but outside I would bind to it using the full name message
. For example: <my-directive message='hey!'></my-directive>
.
It was fun creating this custom component, but it was also a disappointment that ionic2 didn't support this feature out of the box, like Android Native did.
- https://www.sitepoint.com/angular-2-components-inputs-outputs/
- https://angular.io/docs/ts/latest/api/core/index/Output-var.html
- https://angular.io/docs/ts/latest/api/core/index/Input-var.html
- https://github.com/smukov/AvI/commit/3da81aab07c123efa1709bf5c156fc349e1a820c
- https://github.com/smukov/AvI/commit/28aea168aa0cec2b15f182ad23726134dc73b84c
- https://github.com/smukov/AvI/commit/d45845a242b03d16d42d6ae221360a678da184ae
- improved chat page, input doesn't lose focus and keyboard stays app on send
- Android
- Getting Started
- Project Structure
- Gradle
- Menu
- Theming
- Login Screen
- Menu & Navigation
- Importing Library From GitHub
- Creating Reusable Layouts
- Adding New Icons
- Profile Screen
- Chat Screen
- Contacts Screen
- Pending Invites Screen
- Settings Screen
- Add Library Dependency
- Discover Users Screen
- Splash Screen
- Auth0
- Authentication Logic
- Profile Screen Logic
- Send Feedback
- Authenticated to Firebase via Auth0
- Saving User Info to Firebase
- Storing User Connection Info to Firebase
- Calculating Distance Between Users
- Chat Logic
- Handling Device Rotation
- Android Other
- Ionic
- Getting Started
- Project Structure
- Menu
- Theming
- Login Screen
- Adding Images
- Creating Reusable Layouts
- Adding New Icons
- Profile Screen
- Contact Screen
- Elastic Textarea
- Chat Bubble
- Chat Screen
- Contacts Screen
- Pending Invites Screen
- Settings Screen
- Discover Users Screen
- Splash Screen
- Animations
- Auth0
- Storing User Data
- Profile Screen Logic
- Send Feedback
- Update to Ionic RC0
- Reimplemented Auth0 with Ionic RC0
- Authenticated to Firebase via Auth0
- Saving User Info to Firebase
- Storing User Connection Info to Firebase
- Calculating Distance Between Users
- Chat Logic
- Handling Device Rotation
- Ionic Other
- Version Updating
- Cordova
- Other
- Messaging