Categories
discuss

How integrate jQuery plugin in React

I want to use https://github.com/t1m0n/air-datepicker with in a React app, but it doesn’t work.

import React from 'react';
import AirDatepicker from 'air-datepicker';

class Datepicker extends React.Component {
  render() {
    return(
      <AirDatepicker />
    )
  }
}

export default Datepicker;
`
<script src="./../bower_components/jquery/dist/jquery.min.js"></script>

This produces:

error($ is not defined)

Another approach:

import React from 'react';
import $ from 'jquery';
import AirDatepicker from 'air-datepicker';

class Datepicker extends React.Component {
  render() {
    return(
      <AirDatepicker />
    )
  }
}

export default Datepicker;

Same error.

How can I integrate a jQuery plugin with React?

Answer

First of all air-datepicker is not React component, it’s jQuery plugin, so it won’t work like in your examples.

Secondly, for proper work, jQuery should be availabel in global context, the most esiest ways to do this is to include it into page via <script> tag. It should be included before plugin script.

To check if its really included and it available globally, just type in Chrome console window.jQueryand press Enter it should return something like function (a,b){...}. If not, when you doing something wrong, check src attribute of <script> tag, maybe it pointing to wrong destination

How to get it worked in React?

Well, the most simpliest way is just to initialize plugin on any DOM element in your component, like in regular JavaScript.

class MyComponent extends React.Component {
  componentDidMount(){
    this.initDatepicker();
  }
  
  initDatepicker(){
    $(this.refs.datepicker).datepicker();
  }
  
  render(){
    return (
      <div>
        <h3>Choose date!</h3>
        <input type='text'  ref='datepicker' />
      </div>    
    )
  }
}

ReactDOM.render(
  <MyComponent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/air-datepicker/2.2.3/js/datepicker.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/air-datepicker/2.2.3/css/datepicker.min.css" rel="stylesheet"/>

<div id="app"></div>

As separate component

Very simple datepicker React component example

class Datepicker extends React.Component {
  componentDidMount(){
    this.initDatepicker();
  }
  
  initDatepicker(){
    $(this.refs.datepicker).datepicker(this.props);
  }

  render(){
    return (
      <input type='text' ref='datepicker'/>
    )
  }
}


class MyComponent extends React.Component {
  render(){
    return (
      <div>
        <h3>Choose date from React Datepicker!</h3>
        <Datepicker range={true} />
      </div>    
    )
  }
}

ReactDOM.render(
  <MyComponent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/air-datepicker/2.2.3/js/datepicker.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/air-datepicker/2.2.3/css/datepicker.min.css" rel="stylesheet"/>

<div id="app"></div>

Also don’t forget to include css files.

Categories
discuss

Can’t find source maps for Karma + Jasmine + TypeScript + Webpack

I’m trying to test (with coverage) my TypeScript application using Karma, Jasmine, and Webpack. With the following, I’m able to successfully run tests, but am unable to generate coverage properly. I’m using karma-remap-coverage (https://github.com/sshev/karma-remap-coverage) and it seems simple enough.

It looks as though something interesting is happening (and I’m getting some kind of coverage report) but with a few tweaks here and there, the numbers change drastically and I can never actually load the sourcemaps.

Here’s the basic setup:

I have a src directory that contains 10 .ts files. Only one has a corresponding .spec file at the moment.

The spec file is pretty simple and was just enough to prove that I could run tests:

import ComponentToTest from './componentToTest';

describe('ComponentToTest', () => {

  it('should run a test', () => {
      expect(1+1).toBe(2);
  });

  it('should be able to invoke the a method', () => {
      spyOn(ComponentToTest, 'foo').and.callThrough();
      ComponentToTest.foo('testing foo');
      expect(ComponentToTest.foo).toHaveBeenCalled();
  });

});

This works like a charm when paired with my tsconfig.json file:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "noImplicitAny": false,
    "sourceMap": true,
    "lib": ["es6", "dom"],
    "experimentalDecorators": true
  },
  "exclude": [
    "node_modules"
  ]
}

and karma.conf.js file:

module.exports = config => config.set({

    frameworks: ['jasmine'],

    mime: { 'text/x-typescript': ['ts','tsx'] },

    // if I make this a generic './src/**/*.ts' it seems to freeze up
    // without throwing any errors or running any tests, but that seems
    // like a separate issue...
    files: [
        './src/lib/componentToTest.ts',
        './src/lib/componentToTest.spec.ts'
    ],

    preprocessors: {
        './src/**/*.spec.ts': ['webpack'],
        './src/**/*.ts': ['webpack', 'sourcemap', 'coverage']
    },

    webpack: {
        devtool: "source-map",
        module: {
            rules: [
                {
                    test: /.ts?$/,
                    loader: 'ts-loader',
                    exclude: /node_modules/
                }
            ]
        },
        resolve: {
            extensions: [".ts", ".js"]
        }
    },

    webpackMiddleware: {
        quiet: true,
        stats: {
            colors: true
        }
    },

    // add both "karma-coverage" and "karma-remap-coverage" reporters
    reporters: ['progress', 'coverage', 'remap-coverage'],

    // save interim raw coverage report in memory
    coverageReporter: {
        type: 'in-memory'
    },

    // define where to save final remaped coverage reports
    remapCoverageReporter: {
        'text-summary': null,
        html: './coverage/html',
        cobertura: './coverage/cobertura.xml'
    },

    colors: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true

});

And finally, I’m launching the tests with a simple Gulp task:

gulp.task('test', function (done) {
  new Server({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true
  }, (exitCode) => {
     done();
     process.exit(exitCode);
  }).start();
});

When run, I get an output that seems (mostly) promising:

Chrome 58.0.3029 (Mac OS X 10.12.3): Executed 1 of 2 SUCCESS (0 secs / 0.002 secs)
Chrome 58.0.3029 (Mac OS X 10.12.3): Executed 2 of 2 SUCCESS (0.026 secs / 0.004 secs)
[Error: Could not find source map for: "app/src/lib/componentToTest.ts"]
[Error: Could not find source map for: "app/src/lib/componentToTest.spec.ts"]

========================= Coverage summary =========================
Statements   : 43.69% ( 322/737 )
Branches     : 15.7% ( 38/242 )
Functions    : 35.47% ( 61/172 )
Lines        : 44.91% ( 322/717 )
====================================================================

So something is happening! Which makes me feel like I’m close. When I browse to my coverage report in a browser, I see both the .spec.ts file and the .ts file listed (which is again, getting closer) but I’m not quite there for a couple of reasons:

  1. The .spec.ts file is being included in the coverage report. Since this is the test file, I do not want to include it.
  2. Source maps are not being properly generated – this is clear from the errors in the console and also from the inability to browse to the specific file’s coverage report.

I do feel like I’m pretty darn close. Is there anything simple that I’m missing or suggestions?

Update:

I realized I was using an older version of Node and thought that may be causing some issues. I upgraded to 6.11.0 and while that didn’t solve anything, it did provide slightly more context:

The errors are being reported by remap-istanbul (no surprise there, really):

CoverageTransformer.addFileCoverage (/app/node_modules/remap-istanbul/lib/CoverageTransformer.js:148:17)

I am using karma-remap-coverage@0.1.4 which uses remap-istanbul@0.8.4 – it seems like there have been issues with remap-istanbul in the past, but not at the version I’m using.

Also using Webpack 2.6.1 and TypeScript 2.3.2

Answer

Well, after several days of trying different things, I’ve finally found a solution that works. I’m not sure specifically what was causing the issue in my first post, but here’s where I’ve ended up. This may be helpful for someone else looking for a really simple TypeScript, Karma, Jasmine, Webpack (with coverage) setup.

  • My file structure and spec file stayed the same.
  • My tsconfig.json updated to:

    {
      "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "noImplicitAny": false,
        "inlineSourceMap": true, // this line
        "sourceMap": false, // and this one
        "experimentalDecorators": true,
        "lib": ["es6", "dom"]
      },
      "exclude": [
          "node_modules"
      ]
    }
    
  • I switched to using the awesome-typescript-loader instead of ts-loader.

  • And finally, my karma.conf.js file now looks like:

    module.exports = config => config.set({
    
        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '',
    
        frameworks: ['jasmine'],
    
        mime: { 'text/x-typescript': ['ts','tsx'] },
    
        files: [
            'node_modules/angular/angular.min.js',
            './src/**/*.ts'
        ],
    
        preprocessors: {
            './src/**/*.ts': ['webpack']
        },
    
        webpack: {
    
            devtool: 'inline-source-map',
            module: {
                rules: [
                    {
                        enforce: 'pre',
                        test: /.js$/,
                        loader: 'source-map-loader',
                        exclude: [
                            'node_modules',
                            /.spec.ts$/
                        ]
                    },
                    {
                        test: /.ts?$/,
                        use: [
                            {
                                loader: 'awesome-typescript-loader',
                                query: {
                                    /**
                                     * Use inline sourcemaps for "karma-remap-coverage" reporter
                                     */
                                    sourceMap: false,
                                    inlineSourceMap: true,
                                    compilerOptions: {
                                        removeComments: true
                                    }
                                },
                            }
                        ]
                    },
                    {
                        enforce: 'post',
                        test: /.(js|ts)$/,
                        loader: 'istanbul-instrumenter-loader',
                        exclude: [
                            /node_modules/,
                            /.spec.ts$/
                        ]
                    },
                    { test: /.html$/, loader: 'html-loader' }
                ]
            },
            resolve: {
                extensions: [".ts", ".js", ".html"]
            },
            externals: {
                angular: "angular"
            }
        },
    
        webpackMiddleware: {
            quiet: true,
            stats: {
                colors: true
            }
        },
    
        // add both "karma-coverage" and "karma-remap-coverage" reporters
        reporters: ['progress', 'coverage', 'remap-coverage'],
    
        // save interim raw coverage report in memory
        coverageReporter: {
            type: 'in-memory'
        },
    
        // define where to save final remaped coverage reports
        remapCoverageReporter: {
            'text-summary': null,
            html: './coverage/html',
            cobertura: './coverage/cobertura.xml'
        },
    
        colors: true,
    
        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['Chrome'],
    
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true
    
    });
    

Final package versions include:

  • node 4.2.6 (I was also able to get this to work with a newer version of node, but need to be here for other reasons)
  • awesome-typescript-loader 3.1.2
  • istanbul-instrumenter-loader 2.0.0
  • jasmine-core 2.5.2
  • karma 1.6.0
  • karma-chrome-launcher 2.0.0
  • karma-coverage 1.1.1
  • karma-jasmine 1.1.0
  • karma-remap-coverage 0.1.4
  • karma-webpack 2.0.3
  • typescript 2.3.2
  • webpack 2.6.1

Now my tests run, there are no errors in the console, and I have a coverage report of the original TypeScript files!

Lots of credit to the folks who put this together (it ended up guiding quite a bit of my final solution): https://github.com/AngularClass/angular-starter/tree/master/config

Categories
discuss

How to interpret the output of -XX:CompileCommand=”print Class::Method” in java

Here is an excerpt of the output that I get when I run the following command (40 is just an arg to the Fibonacci program) :

java -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=”print Fibonacci::fibonacci” Fibonacci 40

Can someone explain the meanings of each data (I presume it means the number of bytes, e.g., main code takes 288 bytes). Also what do the various categories mean – relocation, stubs code, metadata, scopes data, scopes pcs, handler table etc mean ?

...
Compiled method (c2)      93   16       4       Fibonacci::fibonacci (22 bytes)
total in heap  [0xfff8000108113dd0,0xfff8000108114440] = 1648
relocation     [0xfff8000108113f00,0xfff8000108113f48] = 72
main code      [0xfff8000108113f60,0xfff8000108114080] = 288
stub code      [0xfff8000108114080,0xfff80001081141e0] = 352
oops           [0xfff80001081141e0,0xfff80001081141e8] = 8
metadata       [0xfff80001081141e8,0xfff8000108114210] = 40
scopes data    [0xfff8000108114210,0xfff8000108114298] = 136
scopes pcs     [0xfff8000108114298,0xfff80001081143d8] = 320
dependencies   [0xfff80001081143d8,0xfff80001081143e0] = 8
handler table  [0xfff80001081143e0,0xfff8000108114440] = 96
----------------------------------------------------------------------
Fibonacci.fibonacci  [0xfff8000108113f60, 0xfff80001081141e0]  640 bytes
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} {0xfff80001036243b8} 'fibonacci' '(I)J' in 'Fibonacci'
# parm0:    I0        = int
#           [sp+0x90]  (sp of caller)
...

Answer

The hexadecimal numbers between square brackets are the start and end of the memory range that contain the data. As you guessed, the number after the = is the size of the data in bytes.

Regarding the categories:

  • total in heap is the whole compiled code and metadata. It includes all the other categories. It is actually bigger than the sum of all other categories because there are a bunch of other fields that are not described in this table (This table only describes the parts of the object that have variable size).
  • relocation is metadata that allows the VM to patch the code if necessary: for example if the code embeds an object pointer, that pointer needs to be modified if the GC moves the object. It also contains information about inline caches, any reference to external constants, runtime calls etc.
  • main code is the bulk of the native code compiled for that method.
  • stub code this is some more machine code associated with this method. It is usually little pieces of code that are used to support the main code during some runtime events (e.g., linking or re-linking call sites or inline caches, deoptimization, exception handling…)
  • oops An array of Ordinary Object Pointers (i.e., pointers to garbage collected objects). They can be referenced from the main code or scopes data below.
  • metadata Since the removal of the permanent generation in JDK 8, the VM’s metadata about classes and methods are no longer standard garbage collected oops, since they still need to be tracked they got their own section. So metadata are pointers to metadata objects (the VM objects representing classes and methods for example). They can also be referenced from the main code or scopes data below.
  • scopes pcs This contains metadata that allow to go from a program counter in the main native code to a code location in Java: native PCs are mapped to a Java method and bytecode index (“bci”). Because of inlining, a single PC is actually associated with a stack of (method, bci) pairs.
  • scopes data This contains metadata further describing the state of the Java VM at those PCs. It contains data that maps JVM locations (e.g., locals or stack slots) to native locations (e.g., registers or native stack slots). This allows the VM to know where to look for oops during GC as well as to reconstruct the state of the interpreter during deoptimization.
  • dependencies This is a list of “assumptions” the compiler made while compiling this method. Such an assumption could be “class Foo has no subclasses”. This allows the VM to know that this method needs to be invalidated if something later violates this assumption (such as loading a new class which is a subclass of Foo in the previous example).
  • handler table This is a table that allows the VM to know where to continue execution when unwinding because of an exception.
Categories
discuss

Javascript object reorganization with performance

I am working on a problem where I have to group an array of objects from one form into another.

An example is better than 1000 words:

var initialData = [
  {
    house: { id: 1, text: "white" },
    room: { id: 1, text: "red" },
    price: 2.1
  },
  {
    house: { id: 1, text: "white" },
    room: { id: 2, text: "blue" },
    price: 3.1
  },
  {
    house: { id: 1, text: "white" },
    room: { id: 3, text: "red" },
    price: 5.8
  },
  {
    house: { id: 2, text: "black" },
    room: { id: 1, text: "yellow" },
    price: 9.1
  },
  {
    house: { id: 2, text: "black" },
    room: { id: 2, text: "green" },
    price: 7.7
  },
];

And the new object should look like this:

var finalObject = {
  houses: [
    {
      id: 1, text: "white",
      rooms: [
        { id: 1, text: "red", price: "2.1" },
        { id: 2, text: "blue", price: "3.1" },
        { id: 3, text: "red", price: "5.8" }
      ]
    },
    {
      id: 2, text: "black",
      rooms: [
        { id: 1, text: "yellow", price: "9.1" },
        { id: 2, text: "green", price: "7.7" }
      ]
    }
  ]
};

I have to find unique houses with all their rooms and also to add each price from initial object inside room.

I’m wondering which would be the best way to do this since I will have a huge amount of elements?

I have some ideas with multiple loops, but to me it seems a bit too complex my solution.

Update: my question is not the same as the one candidate for duplication because I don’t use lodash, and my object has to be refactored a bit, not just regrouped.

Possible solution (inspired by @Gael’s answer)

finalObject = {}

for (var i = 0; i < initialData.length; ++i) {
  var item = initialData[i];
  var id = item.house.id;
  if(!finalObject[id]) {
    finalObject[id] = item.house;
    finalObject[id].rooms = [];
  }
  var room = item.room;
  room.price = item.price;

  finalObject[id].rooms.push(room);
}

console.log(finalObject);

Answer

Use Array#reduce with a helper object:

var initialData = [{"house":{"id":1,"text":"white"},"room":{"id":1,"text":"red"},"price":2.1},{"house":{"id":1,"text":"white"},"room":{"id":2,"text":"blue"},"price":3.1},{"house":{"id":1,"text":"white"},"room":{"id":3,"text":"red"},"price":5.8},{"house":{"id":2,"text":"black"},"room":{"id":1,"text":"yellow"},"price":9.1},{"house":{"id":2,"text":"black"},"room":{"id":2,"text":"green"},"price":7.7}];

var dict = {}; // helper object
var result = initialData.reduce(function(houses, obj) { // reduce the data
  var house = dict[obj.house.id]; // get the house from the dict by id
  
  if(!house) { // if house wasn't found
    house = Object.assign({}, obj.house, { rooms: [] }); // create a new house object
    houses.push(house); // push it into the array of houses
    dict[house.id] = house; // add it to the dict by id
  }
  
  house.rooms.push(obj.room); // push the room to the current house
  
  return houses;
}, []);

console.log(result);

You can also achieve it using ES6 Map and spread syntax:

const initialData = [{"house":{"id":1,"text":"white"},"room":{"id":1,"text":"red"},"price":2.1},{"house":{"id":1,"text":"white"},"room":{"id":2,"text":"blue"},"price":3.1},{"house":{"id":1,"text":"white"},"room":{"id":3,"text":"red"},"price":5.8},{"house":{"id":2,"text":"black"},"room":{"id":1,"text":"yellow"},"price":9.1},{"house":{"id":2,"text":"black"},"room":{"id":2,"text":"green"},"price":7.7}];

const result = [...initialData.reduce((houses, { house, room }) => { // reduce the data to a Map
  const currentHouse = houses.get(house.id) || Object.assign({}, house, { rooms: [] }); // get the current house from the map by id, or create a new one
  
  currentHouse.rooms.push(room); // push the room to the current house
  
  return houses.set(currentHouse.id, currentHouse); // set the house to the map, and return it
}, new Map()).values()]; // get the values of the map and spread to an array

console.log(result);
Categories
discuss

How to add an attribute with a hyphen in the name to a script element?

I want to do something like this but I get an “Invalid left-hand side in assignment” error.

var s = document.createElement("script");
s.type = "text/javascript";
s.src = "http://example.com/example.js";
s.data-flix-distributor = "12994";

Answer

In case you want to set a property using dot notation then it should be valid identifier other case use bracket notation.

Refer : custom attribute works only with element.getAttribute(“attribute”) but not “element.attribute”


To set an attribute to the element use setAttribute() method.

s.setAttribute('data-flix-distributor', "12994");

Or update in dataset property.

s.dataset['flix-distributor'] = "12994";

// or you can use camelCase to dash-style to use dot notation
s.dataset.flixDistributor = "12994";

Refer : Name conversion in dataset property

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..