Search code examples
htmlcssangularflexboxangular-material

Angular Material Flexbox


After trying all kinds of flexbox approaches, I need to ask for guidance. I have to produce a complex layout for desktop and mobile. However, even the mobile layout needs to change, and I want to start with that.

Here is the first layout I need to accomplish, and i would like to do it with angular / material / flexbox, if that is the best approach for this task. (Bootstrap is not an option for me.)

enter image description here

So far, I have something put together, but it's been a challenge, since I don't fully understand what flexbox features material already provides. The bigger challenger, for me, is to make the box on the right side wrap to the right. Right now, it's underneath the other items. I tried some floating hacks, but that didn't do the trick.

Here is the HTML code I currently have (angular is on the back-end and injects its styles accordingly):

<div class="ps contain">
    <h1 class="mat-h1">Find a Provider</h1>
    <form>
        <mat-expansion-panel class="mat-expansion-panel">
            <mat-expansion-panel-header class="mat-expansion-panel-header">
                <mat-panel-title class="mat-panel-title">Show Advanced Search Options</mat-panel-title>
                <mat-panel-description class="mat-panel-description">This is a summary of the content</mat-panel-description>
            </mat-expansion-panel-header>

            <!-- Items -->
            <div class="psOptionsContainer">
                <div class="psOptions psInfoOptions">
                    <div><mat-checkbox id="anpPsChkbx" class="psChkbx">New Patients</mat-checkbox></div>
                    <div><mat-checkbox id="mhrPsChkbx" class="psChkbx">My Records</mat-checkbox></div>
                    <div><mat-checkbox id="ihcmgPsChkbx" class="psChkbx">Mountain Medical</mat-checkbox></div>
                    <div><mat-checkbox id="slPsChkbx" class="psChkbx">St. John</mat-checkbox></div>
            </div>

            <div class="psOptions psOptionsProviderType">
                <mat-form-field class="mat-form-field ps-mat-form-field">
                    <mat-select name="psProviderType" placeholder="Provider Type">                            
                        <mat-option value="doctor">Doctor</mat-option>
                        <mat-option value="nurse">Nurse</mat-option>
                        <mat-option value="nurse">Dentist</mat-option>
                        <mat-option value="nurse">Chiropractor</mat-option>
                        <mat-option value="nurse">Orthodontist</mat-option>
                    </mat-select>
                </mat-form-field>
            </div>
            <!-- Languages Spoken -->
            <div class="psOptions psOptionsLanguagesSpoken">
                <mat-form-field class="mat-form-field">
                    <mat-select name="psLanguagesSpoken" placeholder="Languages Spoken">
                        <mat-option value="doctor">American</mat-option>
                        <mat-option value="nurse">Belgian</mat-option>
                        <mat-option value="nurse">Chinese</mat-option>
                        <mat-option value="nurse">Danish</mat-option>
                        <mat-option value="nurse">English</mat-option>
                    </mat-select>
                </mat-form-field>
            </div>

            <!-- Gender Preferences -->
            <div class="psOptions psOptionsGenderPreferences">
                <mat-form-field class="mat-form-field">
                   <mat-select name="psGenderOptions" placeholder="Gender Preferences">
                        <!-- <mat-option *ngFor="let ptype of ptypes" [value]="sample.value"> -->
                        <!-- <mat-option>{{ ptype.viewValue }}</mat-option> -->
                        <mat-option value="doctor">Female</mat-option>
                        <mat-option value="nurse">Male</mat-option>
                        <mat-option value="nurse">Other</mat-option>
                    </mat-select>
                </mat-form-field>
            </div>

            <!-- Clinic -->
            <div class="psOptions psOptionsClinic">
                <mat-form-field class="mat-form-field">
                    <mat-select name="psClinic" placeholder="Clinic">
                        <mat-option value="doctor">American Fork</mat-option>
                        <mat-option value="nurse">Murray</mat-option>
                        <mat-option value="nurse">St. George</mat-option>
                    </mat-select>
                </mat-form-field>
            </div>

            <!-- Hospital Affiliation -->
            <div class="psOptions psOptionsHospitalAffiliation">
                <mat-form-field class="mat-form-field">
                    <mat-select name="psHospitalAffiliation" placeholder="Hospital Affiliation">
                        <mat-option value="doctor">American Fork</mat-option>
                        <mat-option value="nurse">Murray</mat-option>
                        <mat-option value="nurse">St. George</mat-option>
                    </mat-select>
                </mat-form-field>
            </div>

        </div>

        <div class="psInfoOptions">
            <div><mat-checkbox id="anpPsChkbx" class="psChkbx">Accepting New Patients</mat-checkbox></div>
            <div><mat-checkbox id="mhrPsChkbx" class="psChkbx">My Health Records</mat-checkbox></div>
            <div><mat-checkbox id="ihcmgPsChkbx" class="psChkbx">Intermountain Medical Group</mat-checkbox></div>
            <div><mat-checkbox id="slPsChkbx" class="psChkbx">St. Luke's</mat-checkbox></div>
        </div>

    </mat-expansion-panel>
   </form>
</div>

And here is my SCSS:

@import '../../../styles.scss';
/* This brings in some general variables and a function ( remy() ) that converts pixels to rem
.ps {
    .psMobile {
        display: none;
    }
    .mat-h1 {
        font-size: remy(32);
        text-align: center;
    }
    .mat-expansion-panel {
        position: inherit;
    }
    .mat-expansion-panel-header {
        position: inherit;
    }
    .mat-panel-title {
        position: inherit;
    }
    .mat-panel-description {
        display: none;
    }
    .psOptionsContainer {
        position: relative;
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;

        -webkit-box-orient: horizontal;
        -webkit-box-direction: normal;
        -ms-flex-direction: row;
        flex-direction: row;

        -ms-flex-wrap: wrap;
        flex-wrap: wrap;

        -webkit-box-pack: flex-start safe;
        -ms-flex-pack: flex-start safe;
        justify-content: flex-start safe;

        .psOptions {
            height: 3rem;
            padding: 0.5rem;
            width: 16.875rem;

            -webkit-box-ordinal-group: 1;
            -ms-flex-order: 0;
            order: 0;

            -webkit-box-flex: 1;
            -ms-flex-positive: 1;
            flex-grow: 1;

            -ms-flex-negative: 1;
            flex-shrink: 1;

            -ms-flex-preferred-size: 25%;
            flex-basis: 25%;

            -webkit-box-flex: 0;
            -ms-flex: 0 1 auto;
            flex: 0 1 auto;

            -ms-flex-item-align: auto;
            align-self: auto;
        }
    }
    .psInfoOptions {
        background-color: orange;
        /* hacks I have tried to get this container to move to the right of everything else: */
            // padding: 1rem;
            // float: right;
            // width: remy(260);
            // top: 0;
    }

    /* $xs is  640px  
       The box on the right is supposed to flow underneath all the other items at this point
    */

    @media screen and (max-width: $xs) {
        .psOptionsContainer {
            display: block;
            width: 100%;
            min-width: 16.875rem;
            /* center the elements: space-around works in IE: worry about this later */
            // -ms-flex-pack: distribute;
            // justify-content: space-around;
         }
         .psOptions {
            display: block;
            width: 90%;
            margin-top: 0.3125rem;
            .mat-form-field {
                /* calculate this later based on breakpoint */
                width: 30rem;
            }
         }
         .psInfoOptions {
            display: inline-block;
        }
    }

Also, I seem to have issues sizing the form elements, since angular material adds multiple HTML elements to each form element. I have studied the available Angular Material guides and documentation, but it eludes me how to figure out the proper way to do this.

This is the second layout I need to accomplish, by the way:

enter image description here

Any suggestions or links to similar examples that do work?


Solution

  • Angular material does not come with responsive behavior.

    You need to use Angular Flex-Layout https://github.com/angular/flex-layout together with Angular Material

    Take a look here https://tburleson-layouts-demos.firebaseapp.com/#/responsive for how resposive behavior works in Angular Flex-Layout

    OR

    Use css only using flex-box Here's a good guide https://css-tricks.com/snippets/css/a-guide-to-flexbox/