Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular PrimeNG. PrimeFlex: input field not behaving as expected

I am working on an Angular 7 application using PrimeNG and Primeflex. While trying to style a form based component, I have trouble with <input pInputText ...> elements not respecting the prime-flex styling (or at least not behaving as I would expect).

Summary of issue

(Variant 1)

I am enclosing both a <label> and <input> element in two nested <div> elements which are styled with class="p-grid" and class="p-col-*".

<div class="p-grid">
  <div class="p-col-8">
    <label for="description">Description</label><br/>
    <input id="description" pInputText formControlName="description">
  </div>
  <div class="p-col-4">
    <label for="numeric">Numeric</label><br/>
    <input id="numeric" pInputText formControlName="numeric">
  </div>
</div>

I was expecting the <input> field to grow/shrink with the available space, but it seems to have a fixed width that does not adjust to the available space or the number of columns I am using.

(Variant 2)

I then tried nesting another p-gridelement within the column-div and giving each element the full width:

<div class="p-grid">
  <div class="p-col-8">
    <div class="p-grid">
    <label class="p-col-12" for="description">Description</label>
    <input class="p-col-12" id="description" pInputText formControlName="description">
  </div>
  </div>
  <div class="p-col-4">
    <div class="p-grid">
    <label class="p-col-12" for="numeric">Numeric</label>
    <input class="p-col-12" id="numeric" pInputText formControlName="numeric">
  </div>
  </div>
</div>

This does indeed make the <input> field grow to use the available outer column space, but somehow destroys the margin between the columns/fields.

(Variant 3)

After some experimenting I have come up with a solution that does what I want, but it uses incorrect nesting of prime flex classes:

<div class="p-grid">
  <div class="p-col-8">
    <label class="p-col-12" for="description">Description</label>
    <input class="p-col-12" id="description" pInputText formControlName="description">
  </div>
  <div class="p-col-4">
    <label class="p-col-12" for="numeric">Numeric</label>
    <input class="p-col-12" id="numeric" pInputText formControlName="numeric">
  </div>
</div>

This lets the fields grow/shrink in size according to the outer column configuration and maintains the margin between fields/columns. However, as this seems to violate the nesting rules of primeflex as I understood them, I am uncertain if this is indeed the correct way to do this.

Detailed working example showing the problem

The working example can also be found on stackblitz.

Here is a complete working example, based on a default angular project (created with ng new demo):

Modifications to dependencies in package.json (npm i --save primeflex primeicons primeng)

"primeflex": "^1.0.0-rc.1",
"primeicons": "^1.0.0",
"primeng": "^8.0.0-rc.1"

Modifications to angular.json

        "styles": [
          'node_modules/primeicons/primeicons.css',
          'node_modules/primeng/resources/primeng.min.css',
          'node_modules/primeflex/primeflex.css',
          'node_modules/primeng/resources/themes/nova-light/theme.css',
          "src/styles.css"
        ],

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {PanelModule} from 'primeng/panel';
import {AutoCompleteModule} from 'primeng/autocomplete';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';
import { ListComponent } from './list.component';
import { DetailComponent } from './detail.component';
import { LeftComponent } from './left.component';
import { RightComponent } from './right.component';

@NgModule({
  declarations: [
    AppComponent,
    ListComponent,
    DetailComponent,
    LeftComponent,
    RightComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    PanelModule,
    AutoCompleteModule,
    FormsModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
  <ng-container>
    <h3>Title</h3>
    <div class="container">
      <app-list></app-list>
      <app-detail></app-detail>
    </div>
  </ng-container>`,
  styles: [`
    div.container {
      display: flex;
      flex-wrap: nowrap;
    }
    app-list {
      flex: 0 0 auto;
    }
    app-detail {
      flex: 1 0 auto;
    }`
  ]
})
export class AppComponent {
  title = 'demo';
}

list.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-list',
  template: `
  <p-panel [header]="'List'">
    <div class="item" *ngFor="let item of items">
        <div>{{item}}</div>
    </div>
  </p-panel>` 
})
export class ListComponent {
  items: string[] = ['Item 1', 'Item 2', 'Item 3'];
}

detail.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-detail',
  template: `
  <div class="left">
    <p-panel [header]="'Left'">
        <app-left></app-left>
    </p-panel>
  </div>
  <app-right></app-right>`,
  styles: [':host { display: flex; } div.left{ flex: 1 0 auto; padding: 0 15px; }  app-right { flex: 0 1 50%; }']
})
export class DetailComponent {
}

left.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-left',
  template: '<p>left works!</p>'
})
export class LeftComponent {
}

right.component.ts

(Choose which version of right*.component.html by uncommenting the correct lines. The order of these correspond to the order I used to present my three approaches above)

import { Component, OnInit } from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms';

@Component({
  selector: 'app-right',
// --> choose variant by activating one of the three following lines
  templateUrl: './right1.component.html'
//  templateUrl: './right2.component.html'
//  templateUrl: './right3.component.html'
})
export class RightComponent implements OnInit {
  form: FormGroup;

  items: string[] = ['Austria','France','Germany','Italy','Liechtenstein','Switzerland'];

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.form = this.buildForm();
    this.fillForm();
  }

  buildForm(): FormGroup {
    return this.fb.group({
      id1: [{value: '', disabled: true}],
      id2: [{value: '', disabled: true}],
      id3: [{value: '', disabled: true}],
      auto: [{value: '', disabled: true}],
      description: [{value: '', disabled: true}],
      numeric: [{value: '', disabled: true}],
      field1: [{value: '', disabled: true}],
      field2: [{value: '', disabled: true}],
      field3: [{value: '', disabled: true}],
      field4: [{value: '', disabled: true}]
    });
  }

  fillForm() {
    this.form.controls.id1.setValue('42');
    this.form.controls.id2.setValue('666');
    this.form.controls.id3.setValue('314152');
    this.form.controls.auto.setValue('Germany');
    this.form.controls.description.setValue('Short text');
    this.form.controls.numeric.setValue('2345');
    this.form.controls.field1.setValue('foo');
    this.form.controls.field2.setValue('bar');
    this.form.controls.field3.setValue('baz');
    this.form.controls.field4.setValue('Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
  }
}

right1.component.html (Variant 1)

<p-panel [header]="'Right 1'">
  <form [formGroup]="form" class="container">

  <div class="p-grid">
      <div class="p-col-12">
        <label for="id">ID</label>
        <div>
          <input pInputText id="id" formControlName="id1">
          <input pInputText formControlName="id2">
          <input pInputText formControlName="id3">
        </div>
      </div>
    </div>


  <h3>Grouped Information</h3>
    <div class="p-grid">
      <div class="p-col-12">
        <label for="auto">Autocomplete</label>
        <p-autoComplete
          id="auto"
          formControlName="auto"
          [suggestions]="items"
          [style]="{width: '100%'}">
        </p-autoComplete>
      </div>
    </div>
    <div class="p-grid">
      <div class="p-col-8">
        <label for="description">Description</label><br/>
        <input id="description" pInputText formControlName="description">
      </div>
      <div class="p-col-4">
        <label for="numeric">Numeric</label><br/>
        <input id="numeric" pInputText formControlName="numeric">
      </div>
    </div>


    <h3>More grouped information</h3>
    <div class="p-grid">
      <div class="p-col-3">
        <label for="field1">Field 1</label><br/>
        <input id="field1" pInputText formControlName="field1">
      </div>
      <div class="p-col-3">
        <label for="field2">Field 2</label><br/>
        <input id="field2" pInputText formControlName="field2">
      </div>
      <div class="p-col-3">
        <label for="field3">Field 3</label><br/>
        <input id="field3" pInputText formControlName="field3">
      </div>
      <div class="p-col-3">
        <label for="field4">Field 4</label><br/>
        <input id="field4" pInputText formControlName="field4">
      </div>
    </div>
  </form>
</p-panel>

right2.component.html (Variant 2)

<p-panel [header]="'Right 2'">
  <form [formGroup]="form" class="container">

  <div class="p-grid">
      <div class="p-col-12">
        <label for="id">ID</label>
        <div>
          <input pInputText id="id" formControlName="id1">
          <input pInputText formControlName="id2">
          <input pInputText formControlName="id3">
        </div>
      </div>
    </div>


  <h3>Grouped Information</h3>
    <div class="p-grid">
      <div class="p-col-12">
        <label for="auto">Autocomplete</label>
        <p-autoComplete
          id="auto"
          formControlName="auto"
          [suggestions]="items"
          [style]="{width: '100%'}">
        </p-autoComplete>
      </div>
    </div>
    <div class="p-grid">
      <div class="p-col-8">
        <div class="p-grid">
        <label class="p-col-12" for="description">Description</label>
        <input class="p-col-12" id="description" pInputText formControlName="description">
      </div>
      </div>
      <div class="p-col-4">
        <div class="p-grid">
        <label class="p-col-12" for="numeric">Numeric</label>
        <input class="p-col-12" id="numeric" pInputText formControlName="numeric">
      </div>
      </div>
    </div>


    <h3>More grouped information</h3>
    <div class="p-grid">
      <div class="p-col-3">
        <div class="p-grid">
        <label class="p-col-12" for="field1">Field 1</label>
        <input class="p-col-12" id="field1" pInputText formControlName="field1">
      </div>
      </div>
      <div class="p-col-3">
        <div class="p-grid">
        <label class="p-col-12" for="field2">Field 2</label>
        <input class="p-col-12" id="field2" pInputText formControlName="field2">
      </div>
      </div>
      <div class="p-col-3">
        <div class="p-grid">
        <label class="p-col-12" for="field3">Field 3</label>
        <input class="p-col-12" id="field3" pInputText formControlName="field3">
      </div>
      </div>
      <div class="p-col-3">
        <div class="p-grid">
        <label class="p-col-12" for="field4">Field 4</label>
        <input class="p-col-12" id="field4" pInputText formControlName="field4">
      </div>
      </div>
    </div>
  </form>
</p-panel>

right3.component.html (Variant 3)

<p-panel [header]="'Right 3'">
  <form [formGroup]="form" class="container">

    <div class="p-grid">
      <div class="p-col-12">
        <label for="id">ID</label>
        <div>
          <input pInputText id="id" formControlName="id1">
          <input pInputText formControlName="id2">
          <input pInputText formControlName="id3">
        </div>
      </div>
    </div>


    <h3>Grouped Information</h3>
    <div class="p-grid">
      <div class="p-col-12">
        <label for="auto">Autocomplete</label>
        <p-autoComplete
          id="auto"
          formControlName="auto"
          [suggestions]="items"
          [style]="{width: '100%'}">
        </p-autoComplete>
      </div>
    </div>
    <div class="p-grid">
      <div class="p-col-8">
        <label class="p-col-12" for="description">Description</label>
        <input class="p-col-12" id="description" pInputText formControlName="description">
      </div>
      <div class="p-col-4">
        <label class="p-col-12" for="numeric">Numeric</label>
        <input class="p-col-12" id="numeric" pInputText formControlName="numeric">
      </div>
    </div>


    <h3>More grouped information</h3>
    <div class="p-grid">
      <div class="p-col-3">
        <label class="p-col-12" for="field1">Field 1</label>
        <input class="p-col-12" id="field1" pInputText formControlName="field1">
      </div>
      <div class="p-col-3">
        <label class="p-col-12" for="field2">Field 2</label>
        <input class="p-col-12" id="field2" pInputText formControlName="field2">
      </div>
      <div class="p-col-3">
        <label class="p-col-12" for="field3">Field 3</label>
        <input class="p-col-12" id="field3" pInputText formControlName="field3">
      </div>
      <div class="p-col-3">
        <label class="p-col-12" for="field4">Field 4</label>
        <input class="p-col-12" id="field4" pInputText formControlName="field4">
      </div>
    </div>
  </form>
</p-panel>

Screenshots illustrating the issue

Variant 1 (not growing/shrinking) enter image description here

Variant 2 (growing/shrinking but missing margins) enter image description here

Variant 3 (working but invalid nesting) enter image description here

like image 910
Urs Beeli Avatar asked Oct 16 '22 13:10

Urs Beeli


1 Answers

Add

style="width: 100%;"

To your inputs in right1.component.html (or define/use a class with width of 100%), for example:

   <input id="description" style="width: 100%;" pInputText formControlName="description">

An input by default is size=20, and is not going to take up the width of the div. The p-col div is growing appropriately, just not the input inside it.

like image 64
Thor Avatar answered Oct 20 '22 11:10

Thor