opal / opal

Ruby ♥︎ JavaScript
https://opalrb.com
MIT License
4.83k stars 331 forks source link

`returnAnObject`.JS.some_function not work correct. #1998

Closed zw963 closed 3 years ago

zw963 commented 7 years ago

Following is attempt to introduce Opal in my project only for a single CDN uploader module:

# app/assets/javascripts/xxx_www/shared/qiniu_uploader.js.rb

require 'opal-jquery'
require 'plupload/plupload.full.min'
require 'plupload/qiniu.min'
require 'pp'

class QiniuUploader
  def initialize(parent=Element, selector='.js-qiniu-uploader-container')
    @uploader = parent.find(selector)
    @preview = @uploader.find('.js-uploader-preview')
    @domain = @preview.data('domain')
    @form = @uploader.closest('form')
    init
  end

  def init
    x = `Qiniu`
    x.JS.uploader(
      {
        runtimes: 'html5,flash,html4',
        browse_button: 'pickfiles',
        uptoken: @preview.data('uptoken'),
        domain: @domain,
        max_file_size: '4mb',
        flash_swf_url: @preview.data('flash-url'),
        save_key: true,
        auto_start: true,
        init: {
          FilesAdded: ->(_up, _files) {
            # ....
          },
          UploadProgress: ->(up, file) {
             # ....
          },
          UploadComplete: ->(_up) {
             # ....
          },
          FileUploaded: ->(_up, _file, info) {
            # ...
    )
  end
end

The error message is:

qiniu.min.self-c56e9bf….js?body=1:3Uncaught domain setting in options is required!

this is caused by when invoke init method, it not recognize the @domain instance variable.

If replace

x = `Qiniu`
x.JS.uploader(
# ...
)

With

x = Native(`Qiniu`)
x.uploader(
   # ...
)

@domain is recognized.

I think there maybe some issue happen with JS ...

Following is Opal version info: (I notice opal-sprockets exist two version)

  * opal (0.10.4)
  * opal-activesupport (0.3.0)
  * opal-jquery (0.4.2)
  * opal-rails (0.9.3)
  * opal-sprockets (0.4.1.0.10.4.3.1.0)
elia commented 7 years ago

@zw963 you're probably passing a full-blown Hash object to a native function, instead try converting it to native before sending it: x.JS.uploader({…}.to_n)

zw963 commented 7 years ago

It worked!

If there exist some document told me about the difference about following arg1 and arg2, that will good.

Native(`jsObject`).method(arg1)

# with

`jsObject`.JS.method(arg2)

What I think is:

form1: a native object, invoke a auto created ruby method(use method missing), which accept a ruby Hash object. form2: a js object, use a special Opal Lexical token(JS), invoke a native function, only accept native arguments

@elia , Does I understand basically correct ?

Thanks

zw963 commented 7 years ago
# example 1
Native(`jsObject`).method(arg1)

# example 2
`jsObject`.JS.method(arg2)

I guess maybe Native wrapper like example 1, which invoke to_n when construct the method_missing for us, but, I think we should mention this in document, Or, just keep same behavior as example 2, we always invoke to_n ourself when invoke a native js function.

Do you think, @elia ?

zw963 commented 7 years ago

I think the better solution is add those content in Opal document, as described in @fkchang this post:

While String, Numeric, and Array objects in Opal are implemented directly with the corresponding Javascript types, Hash requires more to support all the features of Ruby's Hash thus we need to use to_n() to convert it back to a plan Javascript objects when passing to native Javascript functions.
jtoy commented 3 years ago

this is resolved, so please close this!

zw963 commented 3 years ago

this is resolved, so please close this!

Thank you.