1

I would like to add the attribute autoresize=true to a textarea that is drawn using ember-bootstrap in order to use ember-autoresize.

As you can see here, this attribute is not bound, so I cannot simply add it to my template.

I've tried to manipulate the yielded control like so:

{{#bs-form formLayout="vertical" model=email as |form|}}
    {{#form.element controlType="textarea" property="textEdit" as |el|}}
        {{el.control autoresize=true}}
    {{/form.element}}
{{/bs-form}}

But this only works for classNames, not attributes.

What is the simplest way of achieving what I'm trying to do?

Redsandro
  • 11,060
  • 13
  • 76
  • 106

2 Answers2

2

There are two ways to do it.

Both examples assume ember-bootstrap and ember-autoresize are installed.

1. Ad-hoc approach: no configuration needed, but less convenient to use

Use "Custom controls" described here.

Here's an example:

{{#bs-form formLayout="vertical" model=email as |form|}}
    {{#form.element controlType="textarea" property="textEdit" as |el|}}
        {{textarea autoresize=true id=el.id value=el.value class="form-control"}}
    {{/form.element}}
{{/bs-form}}

Demo: https://ember-twiddle.com/4860f5d660dceadc804495d2720f69f6?openFiles=templates.application.hbs%2C

2. Robust approach: configuration needed, but more convenient to use

Override the original textarea component.

Here's the path for the Classic project structure. For Pods or Module Unification, the path will be different.

app/components/bs-form/element/control/textarea.js

Inside that file, do what the autoresize textarea component does, but on top of Ember-Bootstrap's textarea component:

import BootstrapTextareaComponent from 'ember-bootstrap/components/bs-form/element/control/textarea';
import AutoResizeMixin from 'ember-autoresize/mixins/autoresize';
import { computed, get } from '@ember/object';
import { isEmpty, isNone } from '@ember/utils'; 

export default BootstrapTextareaComponent.extend(AutoResizeMixin, {
  autoresize: true,
  shouldResizeHeight: true,
  significantWhitespace: true,
  autoResizeText: computed('value', 'placeholder', {
    get() {
      var placeholder = get(this, 'placeholder');
      var value = get(this, 'value');
      var fillChar = '@';

      if (isEmpty(value)) {
        return isEmpty(placeholder) ? fillChar : placeholder + fillChar;
      }

      if (isNone(value)) {
        value = '';
      }

      return value + fillChar;
    }
  })
});

Then you can invoke the Bootstrap textarea component normally:

{{#bs-form model=this formLayout="vertical" as |form|}}
  {{form.element label="Inline" placeholder="Enter description..." property="appName" controlType="textarea"}}
{{/bs-form}}

Demo: https://ember-twiddle.com/693209c5fd4c2eeae765827f42dbd635?openFiles=templates.application.hbs%2C

The above code will enable autoresizing to all Ember-Bootstrap textareas. If you need granular control, you can also remove autoresize: true from the component definition. This will let you enable autoresizing individually by passing autoresize=true into the {{form.element}} component invocation.

Andrey Mikhaylov - lolmaus
  • 23,107
  • 6
  • 84
  • 133
  • The first implementation would be awesome, but `form.element` already adds the form element, so your implementation will add the form element inside a form element (e.g. textarea inside textarea). The second option looks good too, although foreign to me. However, it results in _"Failed to create an instance of 'component:bs-form/element/control/textarea'. Most likely an improperly defined class or an invalid module export."_ Because I don't understand exactly how this should work, I cannot fix this on my own, even if the mistake is minor. – Redsandro Jun 13 '19 at 21:19
  • `autoresize` without `.js` works. Unfortunately, the actual mixin does not. – Redsandro Jun 13 '19 at 22:13
  • 2
    You could also extend Ember Bootstrap with a custom `textarea-autoresize` control type. [ember-bootstrap-power-select](https://github.com/kaliber5/ember-bootstrap-power-select) might give you some inspiration for that one. – jelhan Jun 14 '19 at 08:25
  • 2
    This comment thread is [being discussed on Meta](https://meta.stackoverflow.com/questions/386168/what-if-someone-is-being-extremely-rude-but-ends-up-answering-correctly). – halfer Jun 18 '19 at 15:23
  • You don't need to inherit anything other than value. In order for the textarea to respect `formLayout`, it simply needs `class="form-control"`. I have updated the answer accordingly. – Andrey Mikhaylov - lolmaus Jun 19 '19 at 08:50
  • I've fixed the second approach and added a demo. – Andrey Mikhaylov - lolmaus Jun 20 '19 at 10:28
-1

It looks like using ember-bootstrap and ember-autoresize together will not work, because even adding the ember-autoresize mixin does not autoresize the textarea, although the mixin is applied successfully as evidenced the class added by ember-autoresize.

Perhaps both plugins trying to manupulate the textarea causes conflicts. Perhaps the latter is not compatible with the former in combination with Ember 3.11.

Alternatively, You can hack a solution together by manipulating data-min-rows on input, like this codepen jquery example.

Quoted for brevity:

// Applied globally on all textareas with the "autoExpand" class
$(document)
    .one('focus.autoExpand', 'textarea.autoExpand', function(){
        var savedValue = this.value;
        this.value = '';
        this.baseScrollHeight = this.scrollHeight;
        this.value = savedValue;
    })
    .on('input.autoExpand', 'textarea.autoExpand', function(){
        var minRows = this.getAttribute('data-min-rows')|0, rows;
        this.rows = minRows;
        rows = Math.ceil((this.scrollHeight - this.baseScrollHeight) / 16);
        this.rows = minRows + rows;
    });

Bootstrap adds jQuery either way. Might as well use it.

Redsandro
  • 11,060
  • 13
  • 76
  • 106