5

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

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
Urs Beeli
  • 746
  • 1
  • 13
  • 30
  • this could use some stackblitz example the amount of code in question is hard to follow – Xesenix Jul 01 '19 at 14:27
  • @Xesenix: thanks, I've never used stackblitz but I'll try to find out how to use it and create a runnable example. – Urs Beeli Jul 02 '19 at 19:07
  • 1
    @Xesenix here is the link to a working stackblitz example: https://stackblitz.com/edit/angular-mfrg2n – Urs Beeli Jul 12 '19 at 19:10
  • by incorrect nesting do you refer to missing p-grid before p-col if thats you problem you should check what styles adds p-grid it adds margins that make anything inside it use full grid cell width. In first case nothing is resizing inside grid cell because classes you have added just describe layout not how content of that layout should behave. In further examples, you add layout deeper into your form structure so it starts to influence it. In third example, you have just chosen not to extend layout to its full width and its not incorrect just different use case. – Xesenix Jul 13 '19 at 00:51
  • Yes, by incorrect nesting I was referring to the inner elements with the p-col classes as direct chidren of the outer p-col elements. Based on the documentation (and previous bootstrap experience), I expected that an intermediate p-grid would be required. – Urs Beeli Jul 14 '19 at 15:23

1 Answers1

6

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.

Thor
  • 251
  • 2
  • 9