angular / flex-layout

Provides HTML UI layout for Angular applications; using Flexbox and a Responsive API
MIT License
5.9k stars 773 forks source link

router-outlet issues #171

Open jmls opened 7 years ago

jmls commented 7 years ago

I am trying to reproduce the "holy grail" layout , but within a <router-outlet>

if I make my component template empty, and in the main html I have this code

        <router-outlet></router-outlet>

        <div class="containerX">
            <div class="colorNested box" fxLayout="column">
                <header>header</header>
                <div id="main" fxLayout fxFlex >
                    <nav fxFlex="1 6 20%" fxFlexOrder > nav </nav>
                    <article fxFlex="3 1 60%" fxFlexOrder > article </article>
                    <aside fxFlex="1 6 20%" fxFlexOrder > aside </aside>
                </div>
                <footer>footer</footer>
            </div>
        </div>

where the "containerX" html is lifted straight from the demo code, my screen looks like this

image

so, now I cut the holy grail from the main html,

 <router-outlet></router-outlet>

and paste the holy grail code into the component html

<div class="containerX">
            <div class="colorNested box" fxLayout="column">
                <header>header</header>
                <div id="main" fxLayout fxFlex >
                    <nav fxFlex="1 6 20%" fxFlexOrder > nav </nav>
                    <article fxFlex="3 1 60%" fxFlexOrder > article </article>
                    <aside fxFlex="1 6 20%" fxFlexOrder > aside </aside>
                </div>
                <footer>footer</footer>
            </div>
        </div>

the screen now looks like this

image

I have tried to add fxLayout="column" to the router-outlet, didn't make a change, so I know I'm missing something obvious ...

I am using the latest git version

thanks

ThomasBurleson commented 7 years ago

Notice the Flex-Layout Demos uses Routing also.

When you route, if you specified a to-be-routed view that is declared in another module, then you must also re-import the FlexLayoutModule.

jmls commented 7 years ago

Hmm, I tried that, added the FlexLayoutModule to my module (as well as the main app module) and now get this : image

If I remove the import from my module (and keep it in the app module) then the screen goes back to the "bars" format

image

Are you aware of any plunker "seed" project for angular-cli and angular-flex so I can try and reproduce my problem in a very simple app ?

ThomasBurleson commented 7 years ago

Try this Plunkr as a template starter: http://plnkr.co/edit/WzfbnAaRBxH8H67B5Di4?p=preview

ThomasBurleson commented 7 years ago

Closing as invalid.

jefbarn commented 7 years ago

This issue is still valid. There is no way to add flex-layout directives to the app host component. Edit: found #76 which is same issue.

magnayn commented 7 years ago

I don't know if it's helpful, but I had the same issue. Basically if I had

<div fxFlexFill fxLayout="column">
  <header>header</header>
  <div id="main" fxLayout="row" fxLayout.xs="column" fxFlex>
      <nav     fxFlex="1 6 20%" fxFlexOrder fxFlexOrder.xs="2"> nav     </nav>
      <article fxFlex="3 1 60%" fxFlexOrder fxFlexOrder.xs="1"></article>
      <aside   fxFlex="1 6 20%" fxFlexOrder fxFlexOrder.xs="3"> aside   </aside>
  </div>
  <footer>My footer</footer>
</div>

With

<div fxFlexFill fxLayout="column">
  <header>header</header>
  <router-outlet class="foo"></router-outlet>
  <footer>My footer</footer>
</div>

(And the inner "main" div generated by the navigated page), then I was getting all sorts of problems.

The issue seems that any element (or pseudo-element) also gets considered for flexbox layout - in this case the router-outlet. (I.E this isn't specifically an angular flex-layout issue) What I did was to make it

<router-outlet class="foo"></router-outlet>

And add the style

.foo {
    flex: 1 1 auto;
    display: flex;
    overflow: hidden;
  }

Which seems to be working for me.

yves-pkstd commented 7 years ago

I am experiencing the same problem. When I put the layout code outside the (nested)router-outlet then everything works fine. When I copy the layout code and put it a loaded template then the layout is all scrambled and is very difficult to position right. Sadly magnay's fix is not working for me.

The thing is that it does get passed my first router-outlet. I am using child views and different layout paths.

if I replace the router-outlet in layout.component with my childview.component content/layout all works just fine. Do I use the original structure and put the layout in my child view again, then it doesn't.

I am loading the MaterialModule and FlexLayoutModule in every module just to be sure and the flex layout still reacts to flex-layout changes made in the child view, although weirdly. This leads me to believe that loading/import wise all is well.

It is the same problem though. Router outlet being considered for flex-layout when it should be ignored. The thing is, this seems like such a major blocking issue to me so I am surprised not more people are reporting this problem. Which makes me believe I must be doing something wrong :)

Will create a plunker when I have time.

magnayn commented 7 years ago

What worked for me (eventually, and there may be better solutions) was

@Component({
             templateUrl: 'patient.page.html',
             host: {class: 'myClass'},

And inside my global styles.css I added

.myClass {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

I don't think there's much that flex-layout can do - it's essentially providing a nice API to declare flexbox directives, but those ultimately boil down to styles applied to elements. Ultimately, despite the "css separates structure from presentation" cheerleading, it's simply not true, as additional elements break your hard-won flexbox layout.

The other thing that helped was simulating my layout in a static HTML file, and mucking about adding <div>s in the layout simulating what happens in router-outlet.

yves-pkstd commented 7 years ago

@magnayn

Thanks. That fix works very well.

Yeah I agree. I was already doing exactly that. Trying to emulate the bug in a router-outlet free template and try to fix it that way. Big thanks for saving me that time.

amirshenhav commented 7 years ago

@magnayn I ran into the same issue. Thanks for the fix!

mackelito commented 7 years ago

I do also have this problem and sure.. we can fix it manually by adding this css but it should not be needed. For some reason the css is not appended to the host element.

Looks like it´s not appending a wrapper div.

issue

The difference for me is the route structure.

    {
      path: '',
      component: UserComponent,
      children: [
        {
          path: '', component: UserDashboardComponent, children: [
            { path: 'ordrar', component: OrdersComponent }, // working
            { path: 'inställningar', component: SettingsComponent }, // working
          ]
        },
        { path: 'skapa-konto', component: RegistrationFormComponent }, // not working
      ]
    },
Wo1v3r commented 7 years ago

Another fix based on @magnayn 's would be using the next sibling selector on router-outlet

router-outlet + * { flex: 1 1 auto ; display: flex ; flex-direction: column ; }

Works for me and saves using host class for all the views (if needed)

gpolyn commented 7 years ago

@Wo1v3r, @magnayn is your use of all the elements in your master class necessary? Specifically, can one omit flex-direction: column and display: flex?

Here is a sample of my adaptation of your fix in Angular.

// src/styles.css

html, body {
  display: flex;
  flex-direction: column;
  margin: 0;
  height: 100%;
}

.myClass {
  flex: 1 1 auto;
  // display: flex;
  // flex-direction: column;
}

And here is a component setup resolved via router-outlet.

@Component({
  selector: 'choice',
  host: {class: 'myClass'},
  styles: ['div {background-color: gray}', 'button {width: 80%}'],
  template: `
    <div fxLayoutAlign="space-around center" fxLayout="column" fxFlex> 
      <button md-raised-button>days</button>
      <button md-raised-button>hours</button>
    </div>
  `
})
...

So, is .myClass { flex: 1 1 auto;} valid as the host no matter what the stylistic uses I make of flex-layout in the routed components?

(Meanwhile, I can ignore @ThomasBurleson on re-importation.)

Wo1v3r commented 7 years ago

@gpolyn Did it solve it? If so it looks cleaner as it falls down to the styles.css.

I think it should be implemented in some way in the Angular Flex Layout itself to avoid using our own flex settings... Could we do it? @ThomasBurleson, TLDR: Using host settings on router outlet to force flex-layout

ngPopeye commented 7 years ago

What worked for me was also setting app-component { display:flex; }

nayfin commented 7 years ago

Here's a plunk with a router-outlet that might help. Seems to being pulling from the head of the repo instead of from npm. I am having trouble reproducing this in my app but I will try pulling from the repo and see if that helps, then update comment.

J-Strong commented 7 years ago

I am having the same issue as @yves-pkstd it seems. I cannot use Angular flex-layout in my child modules. Below is my Router-Tree. I am importing @angular/flex-layout into the main app.module. In my app.component.html I have my first router-outlet. flex-layout works great for the first four components. The problem starts with the children components of the home.module. I again import @angular/flex-layout into the home.module. In my home.component.html I have my second router-outlet and at that point flex-layout no longer works for my children components (ActionComponent and ProfileComponent).

Am I doing something wrong? I tried the solution mentioned above assigning a class to a container div element and using css, but it is not solving my problem. Not being able to use flex-layout in children modules is a huge blocking issue for my project. Currently my project is using Angular 4.2.1 and flex-layout 2.0.0-beta.8. Any help is very much appreciated!

img1

spottedmahn commented 7 years ago

In my component, in my first div, I've added various flex-layout directives. It is adding some flex styles to my-component output tag but not the fxFlex one. What is the expected behavior? Why didn't it add Flex: 1 style?

my-component.html

<div id="container" fxLayout="row" fxFlex fxLayoutAlign="center center"></div>

final output

<my-component style="display: flex; box-sizing: border-box; flex-direction: row;">
    <div id="container" 
        fxflex="" fxlayout="row" fxlayoutalign="center center" 
        ng-reflect-layout="row" ng-reflect-align="center center" ng-reflect-flex="" 
        style="box-sizing: border-box; flex: 1 1 1e-09px; display: flex; flex-direction: row; place-content: center; align-items: center;"></div>
</my-component>

using 2.0.0.-beta.9

VinceBT commented 6 years ago

Thank you @Wo1v3r for the solution, I prefer it this way:

router-outlet.router-flex + * {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
}

and then use:

<router-outlet class="router-flex"></router-outlet>
ThomasBurleson commented 6 years ago

@spottedmahn - fxFlex applies flex: 1 1 1e-09px; as a style to the host element.

nosliwsirhc commented 6 years ago

flex-layout is very poorly documented. The API documentation points to directives and imports which no longer are valid. It's nice in theory but seems to be far from mature. I'm saying this because I've had the same issue with the height not reaching 100% on my routed components and not a single one of the answers work, other than workarounds. Also, unless you have a very specific use case, why put logic into your grid tied to a component TS file? Sometimes higher levels of abstraction obfuscates the underlying tech and makes it impossible to either comprehend or make it's purpose becomes unclear - why work so hard to create something to answer a problem which doesn't exist?

CaerusKaru commented 6 years ago

@nosliwsirhc Docs PRs are welcome. And as a reminder, this library is very much still in beta, and will be for most of this coming year.

If you come up with a novel solution to this issue, you are welcome to submit a PR or add the suggestion here as well. Otherwise, complaining about this will not help. This issue, like every other issue on this repo, is being tracked and we will get to it when the higher priority issues have been sorted out.

aks1994 commented 6 years ago

I have tried using the above sibling class solution but it is not working for me on 5.0.0-beta.15. Here is a stackblitz: https://stackblitz.com/edit/angular-flex-layout-seed-nwmdpw. Any thoughts?

I also tried wrapping the in a

and that too is not working.

I'm still confused whether router-outlets are supported by this library or not.

simeyla commented 5 years ago

The 'sibling' thing won't work if you don't put the css in your main styles.scss.

If you try to put it in app.component.scss it won't work because of the view encapsulation.

This is what I'm doing - I apply .webapp class to root node via a host binding. Some views in my application don't need the full screen flexing - so I only enable this class for certain components.

:host
{
   &.webapp
   {
        ::ng-deep router-outlet.router-flex + * 
        {
            display: flex;
            flex: 1 1 auto;
            flex-direction: column;

            // remove the orange once you've verified it works
            outline: 5px solid orange;

            // hidden seems to be needed to allow child panels to scroll properly
            overflow: hidden;
        }
   }
}

If you want it in app styles you can use ::ng-deep. Thanks to @VinceBT for this idea.

simeyla commented 5 years ago

A lot of people are suggesting flex: 1 1 auto; but be cautious of this in Safari if you have a complex layout. I had some absolutely positioned children and they just vanished when the parent had this on them - presumably because they didn't really have their own size. Switching to flex: 1 1 0px fixed this case for me - so if you're blindly expecting Safari to work just like Chrome it may not always!

lebnic commented 4 years ago

What worked for me (eventually, and there may be better solutions) was

  • in my component (that appears inside router-outlet), I add a style class. E.g:
@Component({
             templateUrl: 'patient.page.html',
             host: {class: 'myClass'},

And inside my global styles.css I added

.myClass {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

I don't think there's much that flex-layout can do - it's essentially providing a nice API to declare flexbox directives, but those ultimately boil down to styles applied to elements. Ultimately, despite the "css separates structure from presentation" cheerleading, it's simply not true, as additional elements break your hard-won flexbox layout.

The other thing that helped was simulating my layout in a static HTML file, and mucking about adding <div>s in the layout simulating what happens in router-outlet.

Thanks for your suggestion, it helped me a lot. Note that that I decided to implement my solution via ng-deep (instead of using class myClass on the host) :

@Component({
  selector: 'app-patient-page',
  templateUrl: 'patient.page.html',
::ng-deep app-patient-page {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}
stimothy commented 4 years ago

I was able to solve this by using the :host css selector in the routed components css file: > parent_component (containing \<router-outlet>) > > ... > routed_component (component \<router-outlet> routes to) > > routed_component.component.css (css found below) > > routed_component.component.html > > routed_component.component.ts

:host {
  display: flex;
  flex: 1;
}

For reference I found this here: https://www.thecodecampus.de/blog/angular-2-use-hostbindings-set-class/