angular 克隆_使用Angular和Stamplay构建Etsy克隆(第3部分)

angular 克隆

In Parts 1 and 2, we did a lot of work. We managed to:

在第1部分和第2部分中,我们做了很多工作。 我们设法:

  • Set up our backend database and API

    设置我们的后端数据库和API
  • Designed our site

    设计我们的网站
  • Allowed for Facebook and Email registration/login

    允许Facebook和电子邮件注册/登录
  • Let users create products

    让用户创造产品
  • Show off all the great products

    展示所有出色的产品

We did all the above with AngularJS and the Stamplay JS SDK. Part 1 totally dealt with the Stamplay dashboard and setting things up there while Part 2 dealt with our front-end code.

我们使用AngularJS和Stamplay JS SDK进行了上述所有操作。 第1部分完全处理了Stamplay仪表板并在那里进行了设置,而第2部分则处理了我们的前端代码。

In part 3 we'll be working on both the back-end (Stamplay) and the front-end (AngularJS code). Here are the things we'll accomplish to finalize our Etsy store:

在第3部分中,我们将同时开发后端(Stamplay)和前端(AngularJS代码)。 这是我们将完成Etsy商店的最终整理的工作:

  1. Handle charging users for products using Stripe

    使用Stripe处理向用户收费的产品
  2. Email the product owner when their product is bought

    购买产品时通过电子邮件发送给产品所有者
  3. Email the user that bought the product when they buy

    购买时向购买该产品的用户发送电子邮件
  4. Handle product searches using Algolia

    使用Algolia处理产品搜索
  5. Wiring up comments for products (we already laid the groundwork for this in part 2)

    撰写产品评论(我们已经在第2部分中为此奠定了基础)
  6. Email a product owner when their product is commented on

    在产品评论中给产品所有者发送电子邮件
  7. View purchase history

    查看购买记录

Luckily for us, Stamplay can help us handle a lot of the search features by talking to the Algolia API for us. They will also let us handle hooking in Stripe easily without a single line of code.

对我们来说幸运的是,Stamplay通过与我们联系Algolia API可以帮助我们处理许多搜索功能。 它们还将使我们无需一行代码即可轻松处理Stripe中的挂钩。

The email notifications will also be handled from the Stamplay dashboard without any code at all thanks to Stamplays API lego/IFTTT like system.

借助Stamplays API lego / IFTTT之类的系统,也可以从Stamplay仪表板处理电子邮件通知,而无需任何代码。

Let's get started with Stripe and charging users (don't worry we'll only be using Stripe's developer mode so no charges will go through).

让我们开始使用Stripe并向用户收费(不用担心,我们将仅使用Stripe的开发人员模式,因此不会收取任何费用)。

带有条纹的产品的充电 (Charging for Products with Stripe)

First things first, let's go to Stripe and create a free account.

首先,让我们转到Stripe创建一个免费帐户。

stripe-home-page

Once you have that, you will find yourself at your new Stripe dashboard. Notice that by default, this account will be in Test mode. No transactions will go through.

一旦有了这些,就可以在新的Stripe仪表板中找到自己。 请注意,默认情况下,该帐户将处于“ 测试”模式。 不会进行任何交易。

stripe-dashboard-test-mode

When normally integrating Stripe, we'd have to go grab our API keys. For future reference, they are located under your account nav in the top right, go to Account Settings. Then go to API Keys.

在正常集成Stripe时,我们必须获取API密钥。 为了方便将来参考,它们位于右上角您的帐户导航下,转到帐户设置 。 然后转到API密钥

stripe-dashboard-api-keys

With Stripe however, we don't have to go and grab those and paste them into Stamplay. Stamplay's dashboard is advanced enough to authorize through Stripe directly. With that in mind, let's go over to the Stamplay dashboard to connect Stripe.

但是,有了Stripe,我们不必去抢那些并将其粘贴到Stamplay中。 Stamplay的仪表板足够先进,可以直接通过Stripe授权。 考虑到这一点,让我们转到Stamplay仪表板以连接Stripe。

Under Tasks -> Components we'll see all the integrations that Stamplay can easily set up for us.

在“ 任务”->“组件”下,我们将看到Stamplay可以轻松为我们设置的所有集成。

angular-etsy-stamplay-components

Select Stripe and click Connect. You'll be prompted with a popup to hook in your Stripe account.

选择Stripe,然后单击Connect 。 系统会提示您弹出窗口,以挂接您的Stripe帐户。

angular-etsy-stamplay-stripe-connect

Connect your stripe account and your credentials will automatically be populated for you!

连接您的带区帐户,您的凭据将自动为您填充!

angular-etsy-stamplay-stripe-connected-keys

Live Mode is off by default here so Stamplay will use the Test Public API Key. When we want to start really charging users here, we can flip this switch and then flip the switch in our Stripe dashboard and we're good to go!

默认情况下,“ 实时模式”处于关闭状态,因此Stamplay将使用“ 测试公共API密钥” 。 当我们想在这里开始向用户真正收费时,我们可以翻转此开关,然后在Stripe仪表板中翻转该开关,我们很高兴!

计费电子邮件 (Billing Emails)

There are a couple of things that need to happen as soon as a user buys a product:

用户购买产品后,有几件事需要发生:

  • Email the product owner that their product has been bought

    向产品所有者发送电子邮件,告知他们已经购买了他们的产品
  • Email the user confirming that they purchased a product

    给用户发送电子邮件,确认他们购买了产品

Stamplay makes both of these very simple using their Tasks system. Basically all we need to do in the dashboard is set up tasks that says:

Stamplay使用其“任务”系统使这两者都非常简单。 基本上,我们需要在仪表板中完成的任务是设置以下内容:

  • When a Product is purchased, email the product owner

    购买产品后,请向产品所有者发送电子邮件
  • When a Product is purchased, email the purchaser

    购买产品后,向购买者发送电子邮件

We can do all this without a line of code. Let's take a look. In the Stamplay dashboard, go to Tasks -> Components.

我们无需编写任何代码即可完成所有这些工作。 让我们来看看。 在Stamplay仪表板中,转到Tasks- > Components

We are going to need a service to handle sending emails for us. For this, we'll be using MailChimp's Mandrill service. They help make sending emails easy as we don't have to worry about setting up our own email servers, and handling that whole system.

我们将需要一项服务来为我们处理发送电子邮件。 为此,我们将使用MailChimp的Mandrill服务 。 它们有助于使发送电子邮件变得容易,因为我们不必担心设置自己的电子邮件服务器和处理整个系统。

Let's go over to Mandrill and create an account.

让我们转到Mandrill并创建一个帐户。

mandrill-home-page

Once we have our account, you'll reach the Mandrill dashboard. We are going to need the SMTP address and an API key. We'll find those under Settings.

拥有帐户后,您将进入Mandrill仪表板。 我们将需要SMTP地址和API密钥。 我们将在“设置”下找到这些内容。

I've gone ahead and created a new API Key with the Angular Etsy Stamplay Demo description.

我已经开始并使用Angular Etsy Stamplay演示说明创建了一个新的API密钥。

mandrill-email-api-keys

With that in hand, let's go back to the Stamplay dashboard and enter in our credentials. Under Tasks -> Components, click on the Mandrill logo and enter in your credentials.

有了这些,让我们回到Stamplay仪表板并输入我们的凭据。 在“ 任务”->“组件”下 ,单击“ Mandrill”徽标,然后输入您的凭据。

00-angular-etsy-stamplay-mandrill-connected

创建我们的首要任务(向用户发送电子邮件) (Creating Our First Tasks (Emailing a User))

With Mandrill connected, we can create our email task. Go to Tasks -> Manage and let's create a new task.

连接Mandrill后,我们可以创建电子邮件任务。 转到任务->管理 ,让我们创建一个新任务。

01-angular-etsy-stamplay-manage-tasks

Click New Task and we'll see a very simple when-then interface. Remember in part 1 that we created an Order custom object. The trigger will be when an Order object is created and the action will be Send an Email. Let's configure that now:

单击“ 新建任务” ,我们将看到一个非常简单的“再入时”界面。 请记住,在第1部分中,我们创建了Order自定义对象。 触发器将在创建Order对象时执行,操作将是“发送电子邮件”。 现在配置一下:

02-angular-etsy-stamplay-create-email-task

Next we move on to configure the trigger of this task. In our case, we want to trigger this on creation of a new order.

接下来,我们继续配置此任务的触发器。 在我们的案例中,我们想在创建新order触发此操作。

03-angular-etsy-stamplay-email-trigger

The next step is to configure our transactional message through Mandrill. Per the Manrdill messages docs, we are going to send our email as a JSON object.

下一步是通过Mandrill配置我们的交易消息。 根据Manrdill消息文档 ,我们将以JSON对象的形式发送电子邮件。

Here is the format of our JSON object:

这是JSON对象的格式:

{
  "message": {
    "html": "<p>Thanks for your purchase of {{coinstance.product.name}}</p>",
    "subject": "Your Purchase",
    "from_email": "chris@scotch.io",
    "from_name": "Chris Sevilleja",
    "to": [
      {
        "email": "{{user.email}}",
        "name": "{{user.displayName}}",
        "type": "to"
      }
    ]
  }
}

Stamplay let's us conveniently enter in fields from our trigger data (order) and the user that created the order. Just click on the fields to the right to populate that data. You can see we used that in the to fields with {{user.email}}.

Stamplay让我们方便地在触发数据(订单)和创建订单的用户中输入字段。 只需单击右侧的字段即可填充该数据。 您可以看到我们在{{user.email}}to字段中使用了它。

The last step is to name this task (New Order - Customer) and be on our way!

最后一步是命名此任务(“ 新订单-客户” ),然后开始执行!

结帐系统 (The Checkout System)

This will deal with the front-end side of things. We'll use Angular controllers and services to interact with our Stamplay API when a user checks out. The main things we are going to accomplish is to:

这将处理前端的问题。 当用户签出时,我们将使用Angular控制器和服务与Stamplay API进行交互。 我们要完成的主要任务是:

  • Charge a user through Stripe

    通过Stripe向用户收费
  • Create a new order (custom Stamplay object)

    创建一个新订单(自定义Stamplay对象)

We already built the routes, views, and Angular controller out for this page in part 2, so all we have to do is fill out the view and the functionality in the controller.

我们已经在第2部分中为该页面构建了路线,视图和Angular控制器 ,因此我们要做的就是填写视图和控制器中的功能。

向用户收费 (Charging a User)

To charge a user, we will need to pull in the Stripe JS SDK. Then the Stamplay JS SDK comes with a Stripe object so that we can create charges, customers, subscriptions, and more.

要向用户收费,我们需要引入Stripe JS SDK。 然后,Stamplay JS SDK附带了Stripe对象,以便我们可以创建费用,客户,订阅等。

We're going to add and configure the Stripe SDK by adding the following line to our index.html file:

我们将通过在index.html文件中添加以下行来添加和配置Stripe SDK:

<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script>
  Stripe.setPublishableKey('pk_test_2DPyHPUmEw5O14d35FocF5nF');
</script>

Now that we have that configured, we can create the functions to charge a customer and create an order in our OrderService.js file.

现在我们已经配置好了,我们可以创建用于向客户收费的功能,并在OrderService.js文件中创建订单。

Let's add the following to app/shares/OrderService.js:

让我们将以下内容添加到app/shares/OrderService.js

We have three main functions here:

我们在这里有三个主要功能:

  • create: This will be used at checkout to create a new order (by creating a new order, we will also fire off those email tasks we set up in the dashboard)

    create :将在结帐时用于创建新订单(通过创建新订单,我们还将触发在仪表板上设置的那些电子邮件任务)
  • charge: This will use the Stripe SDK to create a credit card token (no credit card data ever leaves the users client browser) and then the Stamplay JS SDK will help us handle the charge by using the Stripe token.

    charge :这将使用Stripe SDK创建信用卡令牌(没有信用卡数据会离开用户客户端浏览器),然后Stamplay JS SDK将帮助我们使用Stripe令牌处理费用。
  • history: This will let us view the purchase history of a user.

    历史记录 :这将使我们查看用户的购买历史记录。
// OrderService.js
angular 
  .module('OrderService', [])
  .factory('Order', ['$stamplay', '$q', '$http', OrderService]);

function OrderService($stamplay, $q, $http) {

  return {
    create: create,
    charge: charge,
    history: history
  };

  /**
   * Create a new order
   */
  function create(data) {
    var def = $q.defer();

    // instantiate a new order model from the stamplay js sdk
    var order = new $stamplay.Cobject('orders').Model;    

    // loop over the fields in data and update the order
    angular.forEach(data, function(value, key) {
      order.set(key, value);
    });

    // save the object
    order.save()
      .then(function() {
        def.resolve(order);
      });

    return def.promise;
  }

  /**
   * Charge a customer
   */
  function charge(userID, price, cardData) {
    var def = $q.defer();

    // create the card token
    Stripe.card.createToken(cardData, function(status, response) {
      // we now have the card token
      var token = response.id;

      // use the stamplay sdk to charge the user
      price = price * 100; // turn the price into pennies
      var customer = new $stamplay.Stripe(); 

      // charge the customer
      customer.charge(userID, token, price, 'USD')
        .then(function() {
          def.resolve(customer);
        });

    });

    return def.promise;
  }

  /**
   * View all the orders for one user
   */
  function history(userID) {
    var def = $q.defer();

    // instantiate a new orders collection from the stamplay js sdk
    var orders = new $stamplay.Cobject('orders').Collection;
    orders.populate().fetch()
      .then(function() {
        def.resolve(orders);
      });

    return def.promise;
  }

}

Now we can add this to our application in the app.js file:

现在,我们可以将它添加到app.js文件中的应用程序中:

// app.js
angular
  .module('etsyApp', [
    ...
    'OrderService'
  ])

With that added, we can now move onto our checkout controller in app/components/checkout/checkout.js:

添加了该代码后,我们现在可以进入app/components/checkout/checkout.js checkout控制器:

Recall in part 2 that we routed our Buy Now button to this checkout page using ui-sref="checkout({ id: product.listing.id })". This ultimately makes the checkout link look like so: http://angularetsy.stamplayapp.com/#/checkout/55f9cfb09370b34c17434e9d

回想第2部分,我们使用ui-sref="checkout({ id: product.listing.id })" 立即购买”按钮路由到了此结帐页面。 这最终使结帐链接看起来像这样: http : //angularetsy.stamplayapp.com/#/checkout/55f9cfb09370b34c17434e9d

What we're going to do is grab that product id from the url, show that product, let users enter in their user information, and then let them checkout. Real quick, we want to make sure that a user is logged in to purchase, so back in product.html, we're going to conditionally show the Buy Now button or a Login/Signup button.

我们要做的是从URL中获取该产品ID,显示该产品,让用户输入其用户信息,然后让他们签出。 很快,我们要确保用户已登录进行购买,因此回到product.html ,我们将有条件地显示立即购买按钮或登录/注册按钮。

Just replace the Buy Now code with the following:

只需将“立即购买”代码替换为以下代码:

<!-- buy now button links to checkout route -->
<!-- only show buy now button if logged in -->
<a ui-sref="checkout({ id: product.listing.id })" class="listing-buy btn btn-success btn-block" ng-show="currentUser.id">
  Buy Now
</a>
<a ui-sref="authenticate" class="listing-buy btn btn-success btn-block" ng-show="!currentUser.id">
  Login/Signup to Purchase
</a>

Once again, we are utilizing ng-show to conditionally show/hide things.

再一次,我们利用ng-show有条件地显示/隐藏事物。

Now if a user is logged in, they'll be able to click through to the checkout page.

现在,如果用户已登录,则可以单击进入结帐页面。

结帐流程 (The Checkout Process)

Let's handle all the checkout logic now in checkout.js:

让我们把手都在现在结帐逻辑checkout.js

// checkout.js
angular
  .module('app.checkout', [])
  .controller('CheckoutController', ['$stateParams', '$rootScope', 'Product', 'Order', CheckoutController]);

function CheckoutController($stateParams, $rootScope, Product, Order) {
  var checkout             = this;
  checkout.orderData       = {};    // create an empty object to hold order data
  checkout.cardData        = {};    // create an empty object to hold credit card data
  checkout.processPurchase = processPurchase;

  // grab the product by the $stateParams.id
  Product.get($stateParams.id)
    .then(function(data) {
      // since this is a singular Stamplay model that was returned, we can bind instance directly
      checkout.product  = data.instance;

      // grab the product id and set it to an object called orderData
      checkout.orderData.product = [data.get('_id')];
      checkout.orderData.price    = data.get('price');
    });

  /**
   * Process the purchase
   */
  function processPurchase() {
    // clear the success message
    checkout.sucessMessage = '';

    // charge the user first
    Order.charge($rootScope.currentUser.id, checkout.orderData.price, checkout.cardData)
      .then(function(data) {
        // then we will create the order on successful charge
        Order.create(checkout.orderData)
          .then(function(data) {
            // purchase successful
            checkout.successMessage = 'Thanks for your order! Your order number is #' + data.get('_id');
          });
      });

  }
}

One landing on the checkout page, we are grabbing the product that is being purchased using Product.get($stateParams.id). We'll then bind that to checkout.product.

在结帐页面上的一个登陆页面,我们正在获取使用Product.get($stateParams.id)购买的产品。 然后,将其绑定到checkout.product

We'll also start building out our orderData object here by passing in the price and the product ID into the price and product fields.

我们还将通过在priceproduct字段中输入价格和产品ID来开始构建orderData对象。

Then we'll create a processPurchase() function to handle the checkout form. This function is responsible for charging a user's credit card and then creating an order. We're calling the functions we created in OrderService.js: Order.charge() and Order.create().

然后,我们将创建一个processPurchase()函数来处理结帐表单。 此功能负责向用户的信用卡收费,然后创建订单。 我们正在调用在OrderService.js创建的函数: Order.charge()Order.create()

With all that wired up, let's move to the view, checkout.html.

完成所有这些工作后,让我们转到视图checkout.html

<!-- checkout.html -->
<div class="checkout-page">

  <div class="page-header text-center">
    <h1>Purchase {{ checkout.product.name }}</h1>
  </div>

  <div class="row">
  <div class="col-sm-8 col-sm-offset-2 col-md-4 col-md-offset-4">

    <form ng-submit="checkout.processPurchase()" novalidate>

      <!-- BASIC PRODUCT INFO -->
      <h4>Basic Info</h4>

      <div class="form-group">
        <p><strong>Product:</strong> {{ checkout.product.name }}</p>
        <p><strong>Price:</strong> {{ checkout.product.price | currency }}</p>
      </div>

      <!-- COLOR OPTIONS. ONLY SHOW IF OPTIONS EXIST -->
      <div class="form-group" ng-show="checkout.product.color">
        <label>Color</label>
        <select class="form-control" ng-model="checkout.orderData.color" 
          ng-options="color for color in checkout.product.color">         
        </select>
      </div>

      <!-- SIZE OPTIONS. ONLY SHOW IF OPTIONS EXIST -->
      <div class="form-group" ng-show="checkout.product.size">
        <label>Size</label>
        <select class="form-control" ng-model="checkout.orderData.size" 
          ng-options="size for size in checkout.product.size">          
        </select>
      </div>

      <!-- BILLING INFO -->
      <h4>Billing Info</h4>

      <!-- CARDHOLDERS NAME -->
      <div class="form-group">
        <label>Cardholder Name</label>
        <input type="text" class="form-control">
      </div>

      <!-- CREDIT CARD NUMBER -->
      <div class="form-group">
        <label>Card Number</label>
        <input type="text" class="form-control" placeholder="4242 4242 4242 4242" ng-model="checkout.cardData.number">
      </div>

      <!-- CVC AND EXPIRATION -->
      <div class="row">
        <div class="col-sm-6">
          <div class="form-group">
            <label>Card CVC</label>
            <input type="text" class="form-control" placeholder="123" ng-model="checkout.cardData.cvc">
          </div>
        </div>
        <div class="col-sm-6">
          <div class="form-group">
            <label>Card Expiration</label>
            <div class="row">
              <div class="col-sm-6">
                <input type="text" class="form-control" placeholder="08" ng-model="checkout.cardData.exp_month">
              </div>
              <div class="col-sm-6">
                <input type="text" class="form-control" placeholder="2020" ng-model="checkout.cardData.exp_year">
              </div>
            </div>            
          </div>
        </div>      
      </div>      

      <!-- SUCCESS MESSAGE -->
      <div class="alert alert-success text-center" ng-show="checkout.successMessage">
        {{ checkout.successMessage }} 
      </div>

      <!-- CHECKOUT BUTTON -->
      <button type="submit" class="btn btn-success btn-block">Checkout</button>

    </form>

  </div>
  </div>
</div>

Now our page will look like the following:

现在,我们的页面将如下所示:

07-angular-etsy-stamplay-checkout-form

Fill out the form and use the following for your credit card info (Stripe let's us use these test credentials):

填写表格,然后将以下信息用作您的信用卡信息(通过条码,我们使用这些测试凭据):

Name: Anything
Card Number: 4242 4242 4242 4242
CVC: 123
Expiration: Any date in the future (08/2020)

Now when we checkout, we should see everything go according to plan.

现在,当我们结帐时,我们应该看到一切按计划进行。

08-angular-etsy-stamplay-checkout-complete

And if we go into our Stamplay dashboard, we'll see the new order created under Data -> Objects -> Orders:

如果我们进入Stamplay仪表板,我们将看到在Data- > Objects-> Orders下创建的新订单

09-angular-etsy-stamplay-object-created

We can also go over to our Stripe dashboard and see the charge (there are a few here since I tested three times)

我们也可以转到Stripe仪表板并查看费用(自从我测试了三次以来,这里有一些)

10-angular-etsy-stamplay-stripe-dashboard-charged

We're all good now! Charging for products is done. Didn't even have to go digging through the Stripe API to see how to deal with charges through them. The Stamplay SDK made that easy for us.

我们现在都很好! 产品充电完成。 甚至不必深入研究Stripe API来查看如何通过它们处理费用。 Stamplay SDK使我们轻松实现了这一目标。

显示订单历史记录 (Showing Order History)

Let's add purchase history to the Admin section of our site. We already have that capability in the OrderService.js so all we need to do is inject that into admin.js and our AdminController and then grab purchase history.

让我们将购买历史记录添加到我们网站的“ 管理员”部分。 我们已经在OrderService.js拥有该功能,因此我们要做的就是将其注入admin.jsAdminController ,然后获取购买历史记录。

Let's inject it now:

现在让我们注入它:

// admin.js
angular
  .module('app.admin', [])
  .controller('AdminController', ['Product', 'Order', AdminController]);

Now we can use it in the controller:

现在我们可以在控制器中使用它:

// admin.js
function AdminController(Product, Order) {
  ...

  /**
   * Get all the orders
   */
  Order.history()
    .then(function(data) {
      admin.orders = data.instance;
    });

  ...
}

We've gotten all the orders and bound them to the admin.orders object. Now we just have to display them in admin.html:

我们已经获得了所有订单,并将它们绑定到admin.orders对象。 现在我们只需要在admin.html显示它们:

<!-- admin.html -->
...
<div class="col-sm-6">
<div class="well">
  <!-- create a product form -->
  <div class="page-header text-center">
    <h3>Order History</h3>
  </div>

  <table class="table table-striped table-hover table-bordered">
    <thead>
      <tr>
        <th>Order #</th>
        <th>Product</th>
        <th>Price</th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="order in admin.orders">
        <td>{{ order.instance._id }}</td>
        <td>{{ order.instance.product[0].name }}</td>
        <td>{{ order.instance.price | currency }}</td>
      </tr>
    </tbody>
  </table>
</div>
</div>

And just like that, we can see order history! There was a lot of setup in the beginning of our application with the whole components directory and all the services and controllers, but once we have the overall layout of our application good, adding features is a simple task since everything is so organized.

就像这样,我们可以看到订单历史记录! 在我们的应用程序的开头,就进行了很多设置,包括整个组件目录以及所有服务和控制器,但是一旦我们拥有了良好的应用程序总体布局,添加功能就很容易了,因为一切都组织得井井有条。

11-angular-etsy-stamplay-order-history

搜索产品 (Searching for Products)

Just like we did with Stripe integration, we are going to integrate Algolia into our application.

就像我们与Stripe集成一样,我们将Algolia集成到我们的应用程序中。

algolia-home-page

They have a very neat service and handle all the intricacies of search engine technology for us. Once you create your account you'll be shown a clear tutorial, but just go ahead and skip it. Those are if you want to import your own data already.

他们提供非常整洁的服务,并为我们处理了所有复杂的搜索引擎技术。 创建帐户后,系统会为您显示清晰的教程,但请继续并跳过它。 这些是如果您想导入自己的数据。

algolia-tutorial

We currently don't have any so we'll move forward.

我们目前没有任何产品,因此我们将继续前进。

创建索引 (Creating an Index)

An index will be Algolia's way of keeping certain items ready to be searchable. In our case, products.

索引将是Algolia保持某些项目可供搜索的方式。 就我们而言,就是产品。

Click on Indices on the left nav and let's create a product index.

单击左侧导航上的索引 ,然后创建一个产品索引。

12-angular-etsy-stamplay-algolia-create-index

Just enter products as our new index and we're good to go. Stamplay will handle all the other heavy duty work for us like adding a new product to our index whenever a new product is created.

只需输入products作为我们的新索引,我们就很好了。 Stamplay将为我们处理所有其他繁重的工作,例如每当创建新产品时就将新产品添加到索引中。

How will Stamplay do this? With a task of course! Let's go connect Algolia and create that task now.

Stamplay将如何执行此操作? 当然有任务! 让我们连接Algolia并立即创建该任务。

Stamplay和Algolia整合 (Stamplay and Algolia Integration)

Grab your Algolia API credentials under the Credentials nav item. We'll want the Application ID and Admin API Key here.

在“ 凭证”导航项下获取Algolia API凭证。 我们在这里需要Application IDAdmin API Key

13-angular-etsy-stamplay-algolia-api-keys

In the Stamplay dashboard, let's connect Algolia under Tasks -> Components

在Stamplay仪表板中,让我们在Tasks- > Components下连接Algolia。

14-angular-etsy-stamplay-algolia-connect

Now we can create the Stamplay task to add new products to the Algolia index. Under Tasks -> Manage -> New, let's create a new task:

现在,我们可以创建Stamplay任务,以将新产品添加到Algolia索引中。 在Tasks-> Manage-> New下 ,我们创建一个新任务:

15-angular-etsy-stamplay-products-to-algolia

When a new product is created, then we will post data to Algolia. We're going to pass information to Algolia as new lines separated by a |. This is what we'll be passing over to Algolia:

创建新product后,我们会将数据发布到Algolia。 我们将信息传递给Algolia,以换行符( |分隔| 。 这就是我们要传递给阿尔戈利亚的内容:

id | {{coinstance._id}}
name | {{coinstance.name}}
price | {{coinstance.price}}
size | {{coinstance.size}}
description | {{coinstance.description}}
category | {{coinstance.category}}
color | {{coinstance.color}}

16-angular-etsy-stamplay-add-product-to-algolia-config

We'll call this task Add Product -> Algolia.

我们将其称为“ 添加产品-> Algolia”

17-angular-etsy-stamplay-save-algolia-task

Any products added so far will not be indexable by Algolia, but you can create another task to add them to Algolia if a product is updated. You can also create a task to update the Algolia index if a new product let's say gets voted up so users can search via ratings.

到目前为止,任何已添加的产品都无法被Algolia索引,但是如果产品已更新,您可以创建另一个任务以将其添加到Algolia。 如果说某一项新产品获得投票,您还可以创建一个任务来更新Algolia索引,以便用户可以通过评级进行搜索。

Let's create a sample product using the API Console in the Stamplay dashboard and see this product get added to Algolia.

让我们使用Stamplay仪表板中的API控制台创建示例产品,并查看该产品已添加到Algolia。

18-angular-etsy-stamplay-create-sample-product

We can go visit our Algolia dashboard and click on Indices and then Products. We'll see our newly created product there:

我们可以访问我们的Algolia仪表板,然后依次单击“ 索引”和“ 产品” 。 我们将在此处看到我们新创建的产品:

19-angular-etsy-stamplay-product-to-algolia

By default, Algolia let's all attributes be searchable and you can set that under the Ranking tab under Indices. For our demo purposes, we'll keep all attributes indexable. You may want to specify certain indices in your applications as it helps Algolia narrow down searches as fast as possible.

默认情况下,Algolia让所有属性都可搜索,您可以在“ 索引”下的“ 排名”标签下进行设置。 出于演示目的,我们将使所有属性都可索引。 您可能需要在应用程序中指定某些索引,因为它有助于Algolia尽快缩小搜索范围。

You can go ahead and type into the search bar found under the Browse tab and see Algolia do a real-time search. Let's integrate this great feature into our own site now.

您可以继续输入在“ 浏览”选项卡下找到的搜索栏,然后看到Algolia进行实时搜索。 让我们现在将此功能集成到我们自己的站点中。

添加预搜索栏 (Adding a Typeahead Search Bar)

We already have search bar in the header of our Etsy clone, but we haven't done anything with it yet.

我们的Etsy克隆的标题中已经有搜索栏,但是我们还没有做任何事情。

To integrate Algolia, we're going to use Bower again to call in the Algolia Search API and UI Bootstrap for its typeahead directive (we want search results to show up as we type).

为了集成Algolia,我们将再次使用Bower 为其Alphalia typeahead指令调用Algolia Search APIUI Bootstrap (我们希望在键入时显示搜索结果)。

For more on UI Bootstrap read: How to Correctly Use AngularJS and Bootstrap Together

有关UI Bootstrap的更多信息,请阅读: 如何正确一起使用AngularJS和Bootstrap

Let's install both of these with:

让我们用以下两个安装它们:

$ bower install --save algoliasearch angular-bootstrap

Now we can add the <script> to our index.html file:

现在我们可以将<script>添加到我们的index.html文件中:

<!-- index.html -->
<script src="./bower_components/algoliasearch/dist/algoliasearch.angular.js"></script>
<script src="./bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>

We are loading the Angular specific version here so we'll also have to inject the module into our app.js file:

我们在这里加载特定于Angular的版本,因此我们还必须将模块注入到我们的app.js文件中:

// app.js
angular
  .module('etsyApp', [
    ...
    'algoliasearch',
    'ui.bootstrap'
  ])

Since the search bar is available throughout our entire application, we'll be handling this functionality inside of the MainController inside the app.js file.

由于搜索栏在整个应用程序中都可用,因此我们将在app.js文件内的MainController内部处理此功能。

Now that we have loaded the Algolia SDK and injected the module, we have access to an algolia object inside of our application. We're going to add that and a couple other things we need ($q and $state) to the MainController:

现在,我们已经加载了Algolia SDK并注入了模块,我们可以在应用程序内部访问algolia对象。 我们将把它和其他一些我们需要的东西( $q$state )添加到MainController

// app.js
...
.controller('MainController', ['User', '$rootScope', 'algolia', '$q', '$state', MainController]);
...

/**
 * The main controller for our application
 */
function MainController(User, $rootScope, algolia) {

  ...

  // configure algolia
  // grab our credentials from algolia
  var client = algolia.Client('4KRGXPTF7K', '4594f3b07157188f25b3f5a8a7eba04e');
  var index = client.initIndex('products');

  ...

}

That's it for configuring Algolia. It's important to note that the API key used here is the Search-Only API Key. This API Key only has access to search unlike the Admin API Key that we added to the Stamplay dashboard which has permissions to actually add products to our Algolia index.

这就是配置Algolia的过程。 请务必注意,此处使用的API密钥是“ 仅搜索API密钥” 。 与我们添加到Stamplay仪表板的Admin API密钥不同,该API密钥只能访问搜索,该API有权将产品实际添加到我们的Algolia索引中。

With that ready to go, let's create a function to handle searching for products and also a function for what to do when we click on a product that we've searched for.

准备就绪后,让我们创建一个用于处理产品搜索的功能,以及一个当我们单击搜索到的产品时要做什么的功能。

// app.js
function MainController(User, $rootScope, algolia, $q, $state) {

  ...
  main.searchProducts = searchProducts;
  main.searchPicked   = searchPicked;

  /**
   * Use algolia to search for products
   * The typeahead function uses promises which is why we use $q
   */
  function searchProducts(query) {
    var def = $q.defer();

    // do the search
    index.search(query, { hitsPerPage: 10 })
      .then(function(data) {
        // return the found items
        def.resolve(data.hits);
      }, function(content) {
        // return no items
        def.resolve([]); 
      })

    return def.promise;
  }

  /**
   * What to do when an item from the search box is clicked
   * Navigate to that product using ui-routers $state.go
   */
  function searchPicked($item, $model, $label) {
    $state.go('product', { id: $item.id, name: $item.name });
  }

}

Per the UI Bootstrap Typeahead docs, we can use the typeahead directive on our input search bar. Every time a user types into our search box, we are going to call the searchProducts() function.

根据UI Bootstrap Typeahead文档 ,我们可以在输入搜索栏上使用typeahead指令。 每次用户在搜索框中键入内容时,我们都会调用searchProducts()函数。

When a user clicks on a found product, we'll use the searchPicked() function. The typeahead directive gives us access to the $item, $model, and $label objects automatically so we'll use the id to route users to the product they select.

当用户点击找到的产品时,我们将使用searchPicked()函数。 typeahead指令使我们可以自动访问$item$model$label对象,因此我们将使用id将用户路由到他们选择的产品。

Here's the HTML for our new typeahead input box:

这是我们新的typeahead输入框HTML:

<!-- index.html -->
<!-- search form -->
<form class="search-form navbar-form navbar-left">
  <div class="form-group">
  <div class="input-group">
    <input
      type="text"
      class="form-control"
      ng-model="main.query"
      placeholder="Find a Product"
      typeahead="product as product.name for product in main.searchProducts($viewValue)"
      typeahead-on-select="main.searchPicked($item, $model, $label)">
      <div class="input-group-addon">
        <span class="glyphicon glyphicon-search"></span>
      </div>
  </div>
  </div>
</form>

Now we have our new search input box:

现在,我们有了新的搜索输入框:

20-angular-etsy-search-box

And when we start typing into it, we can see results returned from Algolia! Currently we only have the Das Keyboard in there so type in a da and you'll see the result.

当我们开始输入时,我们可以看到从Algolia返回的结果! 目前,我们只有Das键盘在其中,因此输入da即可看到结果。

21-angular-etsy-stamplay-algolia-search-typeahead-working

Note: We have to add a little CSS so that our menu stylings don't make the text white as we hover. You'd probably want to be more specific with your stylings so that the dropdowns don't turn white on hover, but for now we'll add this simple CSS line to override.

注意:我们必须添加一些CSS,以便我们的菜单样式不会在悬停时使文本变白。 您可能希望对样式进行更具体的说明,以使下拉列表在悬停时不会变白,但是现在,我们将添加此简单CSS行以覆盖。

/* style.css */
/* search form ------------------------------------------*/
.search-form a:hover  { color:#333 !important; }

Click on the product that shows up in the dropdown and we'll navigate to that page now. Searching is all good now powered by Algolia so you know that it is highly scalable and flexible.

单击下拉菜单中显示的产品,我们现在将导航至该页面。 搜索现在由Algolia提供支持,因此一切都很好,因此您知道它具有高度的可扩展性和灵活性。

产品评论 (Commenting on Products)

The last thing we'll do to finalize our AngularJS Etsy Clone is to allow users to comment on products. We already built in the functionality for this into the ProductService.js service so we just need to implement it in the ProductController in the product.js file.

完成AngularJS Etsy Clone的最后一件事是允许用户对产品发表评论。 我们已经将其功能内置到ProductService.js服务中,因此我们只需要在product.js文件中的ProductController中实现它即可。

Before we do that however, let's take care of the easy part. We want to email the owner of a product that they have received a new comment. We can do that with a Stamplay task.

但是,在执行此操作之前,让我们先处理简单的部分。 我们想通过电子邮件发送给产品所有者,他们已经收到新评论。 我们可以通过Stamplay任务来做到这一点。

22-angular-etsy-stamplay-email-comment-task

We'll configure the trigger to be a comment on a product. Then we'll use Mandrill to send a message to the product owner. Here is the JSON for that task:

我们将触发器配置为对产品的评论。 然后,我们将使用Mandrill向产品所有者发送消息。 这是该任务的JSON:

{
  "message": {
    "html": "<p>You have a new comment on your product: {{coinstance.product.name}}</p>",
    "subject": "New Comment",
    "from_email": "chris@scotch.io",
    "from_name": "Chris Sevilleja",
    "to": [
      {
        "email": "{{coinstance.owner.email}}",
        "name": "{{coinstance.owner.displayname}}",
        "type": "to"
      }
    ]
  }
}

23-angular-etsy-stamplay-new-email-comment-task

With that out of the way, we are now going to handle adding the actual comments on the product page. On the ProductService.js, we already have the ability to create a comment with the comment() function. Now we'll just wire those into the ProductController (app/components/product/product.js):

有了这些,我们现在将处理在产品页面上添加实际评论。 在ProductService.js ,我们已经可以使用comment()函数创建注释。 现在,我们将它们连接到ProductController (app / components / product / product.js):

// product.js
function ProductController(Product, $stateParams) {
  var product           = this;
  product.createComment = createComment;

  ...

  /**
   * Create a new comment on this product
   */
  function createComment() {
    Product.comment($stateParams.id, product.commentData)
      .then(function(data) {
        // clear the comment form
        product.commentData = {};

        // replace the comments with the new comments returned
        product.listing.actions.comments = data.instance.actions.comments;
      });
  }

}

We've already wired up showing comments in product.html and now we have the ability to create a comment. Next up is to wire up the HTML in product.html to show the comment form to create comments.

我们已经连接了在product.html显示评论的位置,现在我们可以创建评论了。 下一步是连接product.htmlHTML以显示评论表单以创建评论。

<!-- product.html -->
<!-- the comment form -->
<form ng-submit="product.createComment()" class="create-comment">

  <div class="form-group">
    <input type="text" class="form-control" placeholder="What are you thinking?" ng-model="product.commentData.text">
  </div>

  <div class="text-right">
    <button type="submit" class="btn btn-primary">Comment</button>
  </div>

</form>

Now that form is wired up and will call the createComment() function on the ProductController. Let's revamp our comment listing a little bit to add some much needed stylings:

现在,该表单已连接好,并将在ProductController上调用createComment()函数。 让我们修改一下注释列表,添加一些急需的样式:

<!-- product.html -->
<!-- repeat over the comments -->
<div class="listing-comments">
  <div class="comment clearfix" ng-repeat="comment in product.listing.actions.comments | orderBy:'-dt_create'">

    <!-- show an avatar if it exists or a placeholder image -->
    <div class="comment-avatar pull-left">
      <div ng-show="comment.picture">
        <img ng-src="{{ comment.picture }}" class="img-responsive img-circle">
      </div>
      <div ng-show="!comment.picture">
        <img src="http://placebear.com/g/80/80" class="img-responsive img-circle">
      </div>
    </div>

    <div class="comment-content">
      <strong>{{ comment.displayName }}</strong>
      <p>{{ comment.text }}</p>
    </div>

  </div>
</div>

We're just going to loop over the comments like before with a little more HTML. We're also adding the users avatar (or a bear picture if they don't have an avatar). Another thing we're going to do is orderBy the dt_create field so that the newest comments are brought to the top.

我们将像以前一样用更多HTML遍历注释。 我们还添加了用户头像(如果他们没有头像,则添加熊图片)。 我们要做的另一件事是orderBy dt_create字段dt_create以便将最新注释置于顶部。

And some CSS styling to replace our old comment CSS:

还有一些CSS样式来代替我们的旧注释CSS:

/* style.css */
.listing-comments .comment  {
  margin-bottom:30px;
  padding-bottom:20px;
  padding-top:20px;
  border-bottom:1px solid #ECECEC;  
}
.comment .comment-avatar  {
  margin-right:30px;
  text-align:center;
}
.comment .comment-avatar img  {
  margin:0 auto 10px;
}

Now our comments will show up on our product page!

现在,我们的评论将显示在我们的产品页面上!

24-angular-etsy-stamplay-comments

结论 (Conclusion)

That concludes our three part tutorial on building an AngularJS Etsy Clone with Stamplay. Using Stamplay we've been able to:

到此,我们结束了关于用Stamplay构建AngularJS Etsy克隆的三部分教程。 使用Stamplay,我们已经能够:

  • Create our database

    创建我们的数据库
  • Server-side API

    服务器端API
  • Set up a solid foundation for an Angular application

    为Angular应用程序奠定坚实的基础
  • Integrate Facebook and email logins

    整合Facebook和电子邮件登录
  • Integrate Stripe to charge users

    整合Stripe向用户收费
  • Integrated emails through Mandrill

    通过Mandrill集成电子邮件
  • Integrate Algolia to get real-time searching

    与Algolia集成以获得实时搜索
  • Allow users to create products

    允许用户创建产品
  • Upload images through Angular

    通过Angular上传图像
  • Did some Etsy styling

    做了一些Etsy造型

There were many techniques used in these tutorials so I hope that you were able to take away some new things learned that you can use in your own projects.

这些教程中使用了许多技术,所以我希望您能够带走一些可以在自己的项目中使用的新知识。

If you are looking to get an idea or app off the ground quickly and have the stability of a tested backend system, then Stamplay is a great place to start. They can handle so many of the integrations and a lot of the parts of an application that can be time consuming and tedious.

如果您希望快速启动构想或应用程序并拥有经过测试的后端系统的稳定性,那么Stamplay是一个不错的起点。 他们可以处理大量的集成和应用程序的许多部分,这些过程既费时又乏味。

Let Stamplay focus on the backend and API integrations and focus on the things you really want to focus on like design, user experience, and other consumer facing parts of your application.

让Stamplay专注于后端和API集成,专注于您真正想要关注的事物,例如设计,用户体验以及应用程序的其他面向消费者的部分。

This content is sponsored via Syndicate Ads.

该内容是通过辛迪加广告赞助的

翻译自: https://scotch.io/tutorials/build-an-etsy-clone-with-angular-and-stamplay-part-3

angular 克隆

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值