aspnet / JavaScriptServices

[Archived] This repository has been archived
Apache License 2.0
3.03k stars 518 forks source link

v0.9.3 Angular and Bootstrap issues #960

Closed ghost closed 7 years ago

ghost commented 7 years ago

Spent ages on this today trying to figure what I'd broken upgrading from Angular 2 to 4. Hopefully someone will have an idea what I'm missing or it at least helps someone else...

Repro:

Download aspnetcore-spa v0.9.1 (Angular 2.4.5) Remove all the html content from a file eg. \ClientApp\app\components\counter\counter.component.html and copy and paste the below from https://www.w3schools.com/bootstrap/bootstrap_modal.asp

<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">Open Modal</button>

<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
  <div class="modal-dialog">

    <!-- Modal content-->
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal">&times;</button>
        <h4 class="modal-title">Modal Header</h4>
      </div>
      <div class="modal-body">
        <p>Some text in the modal.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
      </div>
    </div>

  </div>
</div>

Click the button and note a modal dialog appears

Do the same thing on v0.9.3 (Angular 4.1.2) as above Note now that when clicking on the button the bootstrap modal dialog now doesn't work

Finally I found that adding the below makes it work, but I don't understand why when both Bootstrap and JQuery are both in package.json

Copy this into index.cshtml in your 0.9.3 project

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.js" type="text/javascript"></script>

and now it works in Angular 4

IAmShipy commented 7 years ago

The bootstrap hamburger menu does not work out of the box. Adding the jquery/bootstrap scripts as described above also fixes the issue.

michelebombardi commented 7 years ago

I've experienced another problem when trying to call the collapse function on .navbar-collapse manually from the navmenu.component.ts:

ngAfterViewInit(): void {
    $(".navbar-collapse").on("click", "li:not('.dropdown')", () => {
        $(".navbar-collapse").collapse("hide");
    });
}

In the console the following error is printed: ERROR TypeError: $(...).collapse is not a function

Moreover, I'm not able to import jquery with

var $: JQueryStatic = require("jquery");

I've both jquery(3.2.1) and @types/jquery installed but VS says Cannot find name 'jQueryStatic'

EDIT I was able to solve these issues by adding these lines at the top of the controller:

import * as $ from 'jquery';
import 'bootstrap';

Now a question, why typings are not found like in the previous versione and I have to import them like this?

ANOTHER ISSUE I've added jquery and bootstrap script files in the Index.cshtml like suggested by @flightlevel :

@* asp-prerender-module="ClientApp/dist/main-server" *@
<app>Loading...</app>

<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
    <script src="~/dist/main-client.js" asp-append-version="true"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js" type="text/javascript">
</script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.js" type="text/javascript"></script>
}

Now I'm able to open the hamburger (drop down) menu on small screen but re-clicking on the menu button it doesn't close :(

Any solution?

MarkPieszak commented 7 years ago

@bm-software Use ngx-bootstrap (https://github.com/valor-software/ngx-bootstrap) as it's Bootstrap done for Angular, so the directives/components all don't use jQuery or anything.

michelebombardi commented 7 years ago

@MarkPieszak ngx-bootstrap suggestion is related to jquery and bootstrap imports in the controller, is that right?

MarkPieszak commented 7 years ago

If you use that instead of bootstrap itself, you won't need jquery, and can just do everything the Angular way. Check out the website/repo for more info. You'll be happier in the long run the more you can stay away from jQuery (when combining with these newer front-end frameworks)

michelebombardi commented 7 years ago

@MarkPieszak I'm trying ngx-bootstrap with this code:

<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
    <div class="navbar-header">
        <button type="button" class="navbar-toggle" (click)="isCollapsed = !isCollapsed">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" > <!-- [routerLink]="['/home']" -->
            <i class="fa fa-lg fa-home" aria-hidden="true"></i>
        </a>
    </div>
    <div class="navbar-collapse" (collapsed)="collapsed($event)" (expanded)="expanded($event)" [collapse]="isCollapsed">
        <ul class="nav navbar-nav">
            <li [routerLinkActive]="['link-active']">
                <a [routerLink]="['/courses']">
                    <!--<span class='glyphicon glyphicon-home'></span>--> Corsi
                </a>
            </li>
            <li [routerLinkActive]="['link-active']" *ngIf="authService.isAdmin()">
                <a [routerLink]="['/subscriptions']">
                    <!--<span class='glyphicon glyphicon-th-list'></span>--> Abbonamenti
                </a>
            </li>
            <li [routerLinkActive]="['link-active']" *ngIf="authService.isAdmin()">
                <a [routerLink]="['/registry']">
                    <!--<span class='glyphicon glyphicon-education'></span>--> Anagrafica
                </a>
            </li>
            <li [routerLinkActive]="['link-active']" *ngIf="authService.isAdmin()">
                <a [routerLink]="['/settings']">
                    <!--<span class='glyphicon glyphicon-education'></span>--> Impostazioni
                </a>
            </li>
        </ul>
        <ul class="nav navbar-nav navbar-right">
            <li>
                <a [routerLink]="['/login']">Logout</a>
            </li>
        </ul>
    </div>
</div>

Now the collapse/expand works well but the slideDown/slideUp animation does not. Is it a problem due to the CollapseDirective?

michelebombardi commented 7 years ago

I'm experiencing a similar issue with bootstrap modals:

TypeError: this.$modal.modal is not a function

This time bootstrap and jquery scripts includes are not enough. The modal won't open with that error.

How to fix?

michelebombardi commented 7 years ago

I found a solution that make all work as expect. Instead of import jquery and bootstrap scripts files from Index.cshtml, I've imported them from app.component.ts (the root component) adding the following lines at the top of the file:

import 'jquery';
import 'bootstrap';

With these I'm able to manage both modals and navmenu as I want to, keeping animations too.

Hope this helps.

ADefWebserver commented 7 years ago

@bm-software - Your solution works. Do you plan to make a pull request? If not I can do it.

MarkPieszak commented 7 years ago

Now the collapse/expand works well but the slideDown/slideUp animation does not. Is it a problem due to the CollapseDirective?

You just add the animations through Angular, letting it know the States you want / etc. It's more manual, but you have full control and you're not depending on dated and extremely large bootstrap & jQuery codebases.

michelebombardi commented 7 years ago

@ADefWebserver I've just created a pull request

SteveSandersonMS commented 7 years ago

Glad you got a solution.

jsinh commented 7 years ago

I spent 2 hours trying to make following work:

<div class="collapse navbar-collapse">
    <ul class="nav navbar-nav navbar-right">
        <li [routerLinkActive]="['active']" class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-user"></span> LoggedIn_User_DisplayName <span class="caret"></span> </a>
            <ul class="dropdown-menu">
                <li><a [routerLink]="['/edit']"><span class="glyphicon glyphicon-star"></span> Edit</a></li>
                <li><a [routerLink]="['/logout']"><span class="glyphicon glyphicon-log-out"></span> LogOut</a></li>
            </ul>
        </li>
    </ul>
</div>

Without adding @bm-software suggested following fix:

import 'jquery';
import 'bootstrap';

to my app.component.ts file - evertime I try to click on the dropdown title link it refresh the page thinking i want to do a navigation to myurl/#

Anyone using this with templates (asp.net core + Angular) and trying to create a NavBar / Menu dropdown in their app will face this problem. Someone new like me adapting Core and Angular would run into lots of problem.

Assuming putting following imports in app.component is not harmful or graceful way to handle described issue.... it would be great if the authors / contributors put a note of this fix on home readme or add above imports (commented by default) with two lines explaining it (in templates) - would reaaaally help. CC: @SteveSanderson @ADefWebserver

Thanks @bm-software again for the note, cheers!

kdcllc commented 7 years ago

@bm-software Thanks for the tip. It makes sense, since webpack will package all of the imports! I ran into the following exception once in awhile now:

Exception: Call to Node module failed with error: Prerendering failed because of error: TypeError: Cannot set property 'emulateTransitionEnd' of undefined
michelebombardi commented 7 years ago

@kdcllc and @jsinh , another PR has been merged some weeks ago with the fix. Adding Bootstrap (and jquery if you need it) import at the top of boot-client is enough and everything will work fine ;)

sweetgecko commented 7 years ago

i had a lot of problems using javascriptservices for angular. two things really helped.
one, as stated before, adding the Import statements for jquery and bootstrap. two, disabling server side prerendering by removing the prerender attribute from the from the <app> root element. this helped with the ...error: Prerendering failed...

also, i had to use vs 0.9.3 because 'latest' versions did not include angular template. maybe that is fixed by now