braintree 托管支付字段客户端未定义 Ember 3.25

braintree hosted payment fields client undefined Ember 3.25

Ember 和 Braintree Hosted Fields 到目前为止不是一个很好的组合,Braintree 支持在这方面没有想法。当表单呈现在页面上时,它会调用创建客户端的操作。客户端未定义。

picture-this-44ac48bef9f8df633632a4d202da2379.js:57 未捕获的类型错误:无法读取未定义的 属性 'client'

组件 hbs

<script src="https://js.braintreegateway.com/web/3.81.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.81.0/js/hosted-fields.min.js"></script>
<div class="demo-frame" {{did-insert this.setupBraintreeHostedFields}}>
  <form action="/" method="post" id="cardForm" >
    <label class="hosted-fields--label" for="card-number">Card Number</label>
    <div id="card-number" class="hosted-field"></div>

    <label class="hosted-fields--label" for="expiration-date">Expiration Date</label>
    <div id="expiration-date" class="hosted-field"></div>

    <label class="hosted-fields--label" for="cvv">CVV</label>
    <div id="cvv" class="hosted-field"></div>

    <label class="hosted-fields--label" for="postal-code">Postal Code</label>
    <div id="postal-code" class="hosted-field"></div>

    <div class="button-container">
    <input type="submit" class="button button--small button--green" value="Purchase" id="submit"/>
    </div>
  </form>
</div>

组件class

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { braintree } from 'braintree-web';

export default class CardPaymentComponent extends Component {

  @action
  setupBraintreeHostedFields() {

    alert('booh');
    var form = document.querySelector('#cardForm');
    var authorization = 'sandbox_24nzd6x7_gyvpsk2myght4c2p';

    braintree.client.create({
      authorization: authorization
    }, function(err, clientInstance) {
      if (err) {
        console.error(err);
        return;
      }
      createHostedFields(clientInstance);
    });

    function createHostedFields(clientInstance) {
      braintree.hostedFields.create({
        client: clientInstance,
        styles: {
          'input': {
            'font-size': '16px',
            'font-family': 'courier, monospace',
            'font-weight': 'lighter',
            'color': '#ccc'
          },
          ':focus': {
            'color': 'black'
          },
          '.valid': {
            'color': '#8bdda8'
          }
        },
        fields: {
          number: {
            selector: '#card-number',
            placeholder: '4111 1111 1111 1111'
          },
          cvv: {
            selector: '#cvv',
            placeholder: '123'
          },
          expirationDate: {
            selector: '#expiration-date',
            placeholder: 'MM/YYYY'
          },
          postalCode: {
            selector: '#postal-code',
            placeholder: '11111'
          }
        }
      }, function (err, hostedFieldsInstance) {
        var tokenize = function (event) {
          event.preventDefault();

          hostedFieldsInstance.tokenize(function (err, payload) {
            if (err) {
              alert('Something went wrong. Check your card details and try again.');
              return;
            }

            alert('Submit your nonce (' + payload.nonce + ') to your server here!');
          });
        };

        form.addEventListener('submit', tokenize, false);
      });
    }

  }

}

package.json

...
"ember-cli": "^3.25.2",
"braintree-web": "^3.81.0",
...

** 最终解决方案 **

不需要 NPM braintree-web。组件 class 无权访问 Braintree Window 对象。将标签移动到 app/index.html,如已接受的答案中所述。

组件 hbs

<article class="rental">
  <form action="/" method="post" id="cardForm">
    <label class="hosted-fields--label" for="card-number">Cardholder Name</label>
    <div id="card-holder-name" class="hosted-field payment"></div>

    <label class="hosted-fields--label" for="card-number">Email</label>
    <div id="email" class="hosted-field payment"></div>

    <label class="hosted-fields--label" for="card-number">Card Number</label>
    <div id="card-number" class="hosted-field payment"></div>

    <label class="hosted-fields--label" for="expiration-date">Expiration Date</label>
    <div id="expiration-date" class="hosted-field payment"></div>

    <label class="hosted-fields--label" for="cvv">CVV</label>
    <div id="cvv" class="hosted-field payment"></div>

    <label class="hosted-fields--label" for="postal-code">Postal Code</label>
    <div id="postal-code" class="hosted-field payment"></div>

    <div class="button-container">
    <input type="submit" class="button" value="Purchase" id="submit"/>
    </div>
  </form>
</article>

<script>
var form = document.querySelector('#cardForm');
var authorization = 'sandbox_24nzd6x7_gyvpsk2myght4c2p';

braintree.client.create({
  authorization: authorization
}, function(err, clientInstance) {
  if (err) {
    console.error(err);
    return;
  }
  createHostedFields(clientInstance);
});

function createHostedFields(clientInstance) {
  braintree.hostedFields.create({
    client: clientInstance,
    styles: {
      'input': {
        'font-size': '1.2em',
        'font-family': 'courier, monospace',
        'font-weight': 'lighter',
        'color': '#ccc'
      },
      ':focus': {
        'color': 'black'
      },
      '.valid': {
        'color': '#8bdda8'
      }
    },
    fields: {
      number: {
        selector: '#card-number',
        placeholder: '4111 1111 1111 1111'
      },
      cvv: {
        selector: '#cvv',
        placeholder: '123'
      },
      expirationDate: {
        selector: '#expiration-date',
        placeholder: 'MM/YYYY'
      },
      postalCode: {
        selector: '#postal-code',
        placeholder: '11111'
      }
    }
  }, function (err, hostedFieldsInstance) {
    var tokenize = function (event) {
      event.preventDefault();

      hostedFieldsInstance.tokenize(function (err, payload) {
        if (err) {
          alert('Something went wrong. Check your card details and try again.');
          return;
        }

        alert('Submit your nonce (' + payload.nonce + ') to your server here!');
      });
    };

    form.addEventListener('submit', tokenize, false);
  });
}
</script>

您可以通过直接脚本标签或在 ember-auto-import 的帮助下使用 npm 模块来使用 Braintree SDK。在您的情况下,您同时使用了两者。

为简单起见,我们使用脚本标签注入SDK。您的代码段中的问题是您正在尝试将脚本标记加载到组件把手文件中。车把(.hbs 文件)无法使用 <script> 标签加载脚本。我们需要将脚本标签移动到 app 文件夹中的 index.html 文件。这将正确加载 SDK 以在组件内部使用。

app/index.html:

<body>
  ...


  <script src="https://js.braintreegateway.com/web/3.81.0/js/client.min.js"></script>
  <script src="https://js.braintreegateway.com/web/3.81.0/js/hosted-fields.min.js"></script>

  {{content-for "body-footer"}}
</body>

正确注入 SDK 后,您可以毫无问题地使用 braintree window 对象。