aurelia / skeleton-navigation

Starter kits for building a standard navigation-style app with Aurelia.
Creative Commons Zero v1.0 Universal
732 stars 513 forks source link

External library reference works in Webpack but not in JSPM within Aurelia #473

Closed vaskokj closed 8 years ago

vaskokj commented 8 years ago

I don't know if this is a framework or build issue or an issue I'm causing.

I am trying to use the Datatables.net library in my Aurelia application.

https://www.npmjs.com/package/datatables.net

I added "datatables.net": "npm:datatables.net@^1.10.11", to my package.json and did jspm install -y and datatables.net was said it was installed.

The issue is that the following code works with the Webpack version of Aurelia. The JSPM build I get the error

mytable.js:15 Uncaught (in promise) TypeError: $(...).DataTable is not a function(…)

The following code works if I put it in the Webpack skeleton.

ViewModel:

import $ from 'jquery';
import dataTable from 'datatables.net';
export class MyTable{
  dataSet = [
      ['Ken','Husband','Home'],
      ['Barbie','Wife','Home']
    ];
  attached(){

    //console.log(dataTable);
    var dataSet = this.dataSet;
    //console.log(dataSet);
    //require( 'datatables.net' )( window, $ );
    $(() =>     $('#example').DataTable({ 
        select: true,
        data: dataSet,
        columns: [
        { title: "Name" },
        { title: "Position" },
        { title: "Office" }

        ]
    }) );
  }
 }

View

<template>
  <div class="container" style="margin-top:20px">
    <div>test datatables</div>
    <table id="example" class="display" width="100%"></table>
  </div>
</template>
EisenbergEffect commented 8 years ago

You need to jspm install the dependency. Webpack uses npm but jspm does not. You also need to make sure it is configured correctly with system.js if there isn't a setup for jspm already.

vaskokj commented 8 years ago

I have been manually adding "datatables.net" : "npm:datatables.net@^1.10.12", to my package.json and running"jspm install -y" this picks up the change and adds it to my config.js "npm:datatables.net@1.10.12": { "jquery": "npm:jquery@2.2.4", "process": "github:jspm/nodelibs-process@0.1.2" },

As you suggested, I cloned a new skeleton-es2016 and ran "jspm install datatables.net=npm:datatables.net". This also seems to accomplish the same goal of adding the dependency to the config.js and package.json, however it is the same issue in both cases. I still get the stack error.

Here is the full stacktrace.

mytable.js:13 Uncaught (in promise) TypeError: $(...).DataTable is not a function(…)attached @ mytable.js:13attached @ aurelia-templating.js:2947attached @ aurelia-templating.js:1016attached @ aurelia-templating.js:1472attached @ aurelia-templating.js:1026attached @ aurelia-templating.js:1472(anonymous function) @ aurelia-framework.js:204

How can I check to see if it configured correctly with system.js? I thought that was what config.js was?

AshleyGrant commented 8 years ago

You might want to read through this: https://github.com/DataTables/DataTables/pull/485

It looks like import $ from 'datatables'; is what you'll need, You'll need to delete the modifications you made to your package.json and config.js files, then run jspm install datatables (or possible jspm install datatables@master).

There's also a more recent issue posted here: https://github.com/DataTables/DataTables/issues/564

You'll probably be able to get more help posting this issue either in the jspm/systemjs repos or the datatables repo. This is an issue you're having with those two libraries, not with Aurelia.

Hope this helps!

vaskokj commented 8 years ago

Ashley,

Thanks for the information.

Well this is a way for me to get something else to work actually. I am trying to get this example to work (https://datatables.net/extensions/responsive/examples/styling/bootstrap.html). which needs several other libraries. The datatables link you provided will work but I end up in the same place as I am now with those libraries (as they aren't in jspm). I have been trying to get datatables.net to work so I could repeat the process with the other libraries I am needing to make this example work. I can get the regular "datatables" to work but NOT "datatables.net". If I use "datatables", when I need the other dependencies, I'm in the same boat

AshleyGrant commented 8 years ago

I'm not sure I follow you. Datatables is datatables.net. what exactly is the difference?

vaskokj commented 8 years ago

Bear with me...

If I install "Datatables" via JSPM and then do the following in my VM I can get datatables to work.

import $ from 'jquery';
import dataTable from 'datatables';

BUT

If I install "Datatables.net" via JSPM (from npm) and then do the same thing in my VM. I get the mytable.js:15 Uncaught (in promise) TypeError: $(...).DataTable is not a function(…)

From more research the difference between the "Datatables" and "Datatables.net" is that the latter contains "overrides". I have no idea why it makes it different or what the "overrides" are doing.

You are probably thinking "ok you got datatables working why do you even need datatables.net", and you would be right except that, to get the example working (https://datatables.net/extensions/responsive/examples/styling/bootstrap.html) it uses 4 different js libraries which are NOT contained within "datatables".

jquery.dataTables.js - https://www.npmjs.com/package/datatables.net dataTables.bootstrap.js - https://www.npmjs.com/package/datatables.net-bs dataTables.responsive.js - https://www.npmjs.com/package/datatables.net-responsive responsive.bootstrap.min.js - https://www.npmjs.com/package/datatables.net-responsive-bs

So to get this working I was simply trying to get datatables.net to work. If I got it working, adding the other 3 wouldn't be an issue.

I posted this same question on stackoverflow and someone stated that the reason it won't work with JSPM is because datatables has "overrides" and datatables.net does not. He linked me to another override for the "dataTables.responsive.js" and "responsive.bootstrap.js" but there was no override for "dataTables.bootstrap.js" and suggested I create it. So right now I'm trying to figure out what an "override" is and how I can apply that to the dataTables.bootstrap.js package.

AshleyGrant commented 8 years ago

You might want to consider simply loading jQuery and datatables.net using script tags. Then you wouldn't need to worry about how to properly import them as modules. You could also use the datatables cdn.

Also, there are forums on datatables.net's website that will hopefully be able to help you more than we can. I'm not sure if any Aurelia team members have used datatables.net with their Aurelia applications.

vaskokj commented 8 years ago

As you suggested and to just make sure the example worked I put that entire datatables example in my index.html (including the table) just to test. I saw the table show up for a split second with the blue orbs. The aurelia app loads and the table disappears (which I would kinda expect).

However, I have no idea how to get the "context" of those libraries within Aurelia. Is there some type of documentation that demonstrates how to do this?

AshleyGrant commented 8 years ago

That's not quite what I suggested. I suggested loading datatables.net and jquery using script tags (just like you would have in the past). They will then be in the global namespace and thus accessible to you without any import. At that point, you simply do something like this: index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Aurelia</title>
    <link rel="stylesheet" href="jspm_packages/npm/font-awesome@4.6.1/css/font-awesome.min.css">
    <link rel="stylesheet" href="styles/styles.css">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>

  <body aurelia-app="main">
    <div class="splash">
      <div class="message">Aurelia Navigation Skeleton</div>
      <i class="fa fa-spinner fa-spin"></i>
    </div>

    <!-- load jquery and datables libaries -->
    <script src="lib/jquery.js"></script>
    <script src="lib/datatables.js"></script>
    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>
      System.import('aurelia-bootstrapper');
    </script>
  </body>
</html>

ViewModel:

export class MyTable{
  dataSet = [
      ['Ken','Husband','Home'],
      ['Barbie','Wife','Home']
    ];
  attached(){
    var dataSet = this.dataSet;
    // $().DataTable is now available globally, no need to import a module
    $(this.tableElement).DataTable({ 
        select: true,
        data: dataSet,
        columns: [
        { title: "Name" },
        { title: "Position" },
        { title: "Office" }

        ]
    });
  }
 }

View

<template>
  <div class="container" style="margin-top:20px">
    <div>test datatables</div>
    <table ref="tableElement" class="display" width="100%"></table>
  </div>
</template>

Notice how I use ref="tableElement" to have the table element become a property on the VM. I can then pass this element to jQuery instead of coming up with a selector. In general, you should use Aurelia to get a reference to any element you want to work with rather than writing brittle jQuery selector code (it becomes especially brittle if you write jQuery selectors in custom elements or custom attributes).

I'm not exactly sure what you mean when you ask about a context though.

vaskokj commented 8 years ago

Thanks but doing what you posted with the skeleton-es2016 I get the same error as before.

mytable.js:9 Uncaught (in promise) TypeError: $(...).DataTable is not a function(…)

I cloned the skeleton-es2016 and then ran npm install and jspm install -y and then modified and changed the files.

Here is the files I changed:

index.html


<html>

<head>
  <title>Aurelia</title>
  <link rel="stylesheet" href="jspm_packages/npm/font-awesome@4.6.1/css/font-awesome.min.css">
  <link rel="stylesheet" href="styles/styles.css">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body aurelia-app="main">
  <div class="splash">
    <div class="message">Aurelia Navigation Skeleton</div>
    <i class="fa fa-spinner fa-spin"></i>
  </div>

  <!-- load jquery and datables libaries -->
  <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.12/js/dataTables.bootstrap.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/responsive/2.1.0/js/dataTables.responsive.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/responsive/2.1.0/js/responsive.bootstrap.min.js"></script>
  <script src="jspm_packages/system.js"></script>
  <script src="config.js"></script>
  <script>
    System.import('aurelia-bootstrapper');
  </script>
</body>

</html>

mytable.js

export class MyTable{
  dataSet = [
      ['Ken','Husband','Home'],
      ['Barbie','Wife','Home']
    ];
  attached(){
    var dataSet = this.dataSet;
    // $().DataTable is now available globally, no need to import a module
    $(this.tableElement).DataTable({ 
        select: true,
        data: dataSet,
        columns: [
        { title: "Name" },
        { title: "Position" },
        { title: "Office" }

        ]
    });
  }
 }

mytable.html

<template>
  <div class="container" style="margin-top:20px">
    <table ref="tableElement" class="table table-striped table-bordered dt-responsive nowrap" width="100%"></table>
  </div>
</template>
doktordirk commented 8 years ago

Try the recent PR here on howto load jquery

vaskokj commented 8 years ago

Do you have a link?

The only thing in the Patch Release from March doesn't mention anything about jQuery.

doktordirk commented 8 years ago

https://github.com/aurelia/skeleton-navigation/pull/471 Like with script Tag but different. Import datatables just like usually (or chain another then)

PS. Use/add there window.$=jquery

vaskokj commented 8 years ago

I get the same issue with your suggestion.

If I do

import * as dataTable from 'datatables.net';

dataTable.default(window, $);

from the following defect that Ashley linked, the base version of datatables works.

https://github.com/DataTables/DataTables/issues/564

But I'm still at the same place, the example does not work because I dataTables still needs the following dependencies.

dataTables.bootstrap.min.js
dataTables.responsive.min.js
responsive.bootstrap.min.js

I go add them

jspm install datatables.net-responsive=npm:datatables.net-responsive
jspm install datatables.net-responsive-bs=npm:datatables.net-responsive-bs
jspm install datatables.net-bs=npm:datatables.net-bs

Import them in my VM

import 'datatables.net-responsive';
import 'datatables.net-responsive-bs';
import 'datatables.net-bs';

The Datatable loads, but I don't see any changes to the table like it shows in the example link. I see no errors, I check the network and see all 4 of the libraries loaded correctly. I'm taking a wild guess that it isn't being found. As for why, I have no clue because IE/Chrome/FF do not show a single error message of missing dependencies or anything.

doktordirk commented 8 years ago

well, if all loads now, i guess that part is fine and now you probably need to check if

  attached(){
   let sampleElement = $('#example');
    let table = sampleElement.DataTable({ 
        select: true,
        data: dataSet,
        columns: [
        { title: "Name" },
        { title: "Position" },
        { title: "Office" }
        ]
    });
}

so mabye see what console(sampleElement) and console.log(table) yields

vaskokj commented 8 years ago

What should I be looking for to see why the other libraries wouldn't be working/functioning correctly in the console.log outputs?

The class information on the table looks correct.

https://gist.github.com/vaskokj/d1461409815192beb7c31d59aaeff429

doktordirk commented 8 years ago

Try behind the import DataTable dataTable(window, $); Or so

vaskokj commented 8 years ago

Goes back to the same issue, that we had before dataTable.

mytable.js:17 Uncaught (in promise) TypeError: sampleElement.DataTable is not a function(…)

doktordirk commented 8 years ago

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Aurelia</title>
    <link rel="stylesheet" href="jspm_packages/npm/font-awesome@4.6.1/css/font-awesome.min.css">
    <link rel="stylesheet" href="styles/styles.css">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>

  <body aurelia-app="main">
    <div class="splash">
      <div class="message">Aurelia Navigation Skeleton</div>
      <i class="fa fa-spinner fa-spin"></i>
    </div>

    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>
      // ensure jQuery is loaded and set before other imports in you project
      System.import('jquery')
        .then(jquery => {
          window.jQuery = jquery;
          window.$ = jquery;

          // now load and bootstrap aurelia
          return System.import('aurelia-bootstrapper');
        });
    </script>
  </body>
</html>

welcome.html

<template>
  <section class="au-animate">
    <div class="container" style="margin-top:20px">
      <div>test datatables</div>
      <table id="example" class="table table-striped table-bordered dt-responsive nowrap" width="100%"></table>
    </div>
    </section>
</template>

welcome.js

import * as datatable from 'datatables';
//following only once in you app i think
import * as responsive from 'datatables.net-responsive';
import * as responsiveBs from 'datatables.net-responsive-bs';
import * as netBs from 'datatables.net-bs';

let responsive = responsive.default(); // to change settings?
responsiveBs.default();
netBs.default();

export class Welcome {
  dataSet = [
      ['Ken','Husband','Home'],
      ['Barbie','Wife','Home']
    ];

  attached() {
   // can call: responsive(settings, options);
    $('#example').DataTable({
       select: true,
       data: this.dataSet,
       columns: [
         { title: "Name" },
         { title: "Position" },
         { title: "Office" }
        ]
   });
  }
}
vaskokj commented 8 years ago

The magic...was this... import * as datatable from 'datatables.net'; import * as responsive from 'datatables.net-responsive'; import * as responsiveBs from 'datatables.net-responsive-bs'; import * as netBs from 'datatables.net-bs';

Thanks a ton doktordirk.

amunology commented 8 years ago

@vaskokj This doesn't work for me. I'm having the exact same issue. Can you share with me more details? I'd like to know where I went wrong. I've followed doktordirk's code and was unable to get my table loaded with bootstrap styling. Any thoughts?

amunology commented 8 years ago

@vaskokj : Okay. Mine wasn't working because I didn't add this line -- "netBs.default();" which I find really odd. Anyway, it works now, although the styling is a bit off.