تکمیل کامپوننت Portfolio و نمایش سهام

Complete the Portfolio Component and Display Shares

Vue.JS 2: تکمیل کامپوننت portfolio و نمایش سهام - قسمت 107

در جلسه قبل موفق شدیم که getter ها را برای ماژول portfolio تعریف کنیم و منطق مورد نیاز دکمه Buy را نیز پیاده سازی کنیم اما فعلا هیچ چیزی را برای نمایش در portfolio نداریم. نکته ای را نیز باید به شما بگویم که ممکن است برایتان مشکل ایجاد کرده باشد. در حال حاضر اگر مرورگر را باز کرده و به صفحه stocks بروید (آدرس http://localhost:8080/stocks) باید بتوانید با تغییر مقدار سهام در input ها، روی Buy کلیک کنید. اگر پس از تغییر تعداد سهام از صفر به عددی صحیح مثل 5، دکمه buy همچنان غیرفعال باقی ماند باید کدها را تغییر دهید. به فایل Stock.vue در پوشه stocks بروید و قسمت input را بدین شکل بنویسید:

<div class="pull-left">
  <input
    type="number"
    class="form-control"
    placeholder="Quantity"
    v-model.number="quantity"
  />
</div>

دلیل غیرفعال باقی ماندن Buy این است که ما گفته بودیم اگر مقدار input یک عدد صحیح باشد، دکمه Buy غیرفعال شود. از طرفی در برخی از سیستم ها مقداری که به input می دهیم به عدد تبدیل نمی شود و رشته می ماند بنابراین رشته "5" با عدد 5 یکی نیست و شرط برقرار نمی شود. برای حل این مشکل باید به v-model یک modifier اضافه کنیم (v-model.number) تا رشته به عدد تبدیل شود. توضیحات بیشتر در لینک زیر از documentation وب سایت Vue.js:

https://vuejs.org/v2/guide/forms.html#number

پس از انجام این کار مشکل شما حل خواهد شد. در مرحله بعد باید به فایل portfolio.vue در پوشه components/portfolio برویم و قسمت template آن را به شکل زیر بنویسیم:

<template>
  <div class="col-sm-6 col-md-4">
    <div class="panel panel-info">
      <div class="panel-heading">
        <h3 class="panel-title">
          {{stock.name}}
          <small>(price: {{stock.price}} | Quantity: {{ stock.quantity }})</small>
        </h3>
      </div>
      <div class="panel-body">
        <div class="pull-left">
          <input
            type="number"
            class="form-control"
            placeholder="Quantity"
            v-model.number="quantity"
          />
        </div>
        <div class="pull-right">
          <button
            class="btn btn-success"
            @click="sellStock"
            :disabled="quantity <= 0 || !Number.isInteger(quantity)"
          >Sell</button>
        </div>
      </div>
    </div>
  </div>
</template>

همانطور که می بینید بسیاری از کدها بین این فایل و فایل Stock.vue در پوشه stocks مشترک است. تغییرات ایجاد شده، ساخت دکمه Sell به جای Buy و متد sellStock به جای buyStock است که هنوز آن را تعریف نکرده ایم. البته من کلاس panel-success را به panel-info تغییر داده ام که رنگ پنل ها عوض شود. همچنین در ابتدای صفحه علاوه بر Price، تعداد (quantity) سهام را نیز اضافه کرده ایم. ما به این quantity دسترسی داریم چرا که در فایل portfolio.js (پوشه modules) در متد BUY_STOCK به شکل زیر فیلد های id و quantity را تعریف کرده بودیم:

// بقیه کدها //
if (record) {
    record.quantity += quantity;
} else {
    state.stocks.push({
        id: stockId,
        quantity: quantity
    });
}
// بقیه کدها //

به فایل خودمان (Stock.vue) برمی گردیم. قسمت template را که نوشتیم اما برای قسمت script در این فایل نیز باید متد sellStock را تعریف کنیم:

<script>
export default {
  props: ["stock"],
  data() {
    return {
      quantity: 0
    };
  },
  methods: {
    sellStock() {
      const order = {
        stockId: this.stock.id,
        stockPrice: this.stock.price,
        quantity: this.quantity
      };
    }
  }
};
</script>

بنابراین شباهت بین این دو کامپوننت بسیار زیاد است. البته متد sellStock هنوز کامل نیست و باید action مورد نظرش را صدا بزنیم. برای این کار می گویم:

export default {
  props: ["stock"],
  data() {
    return {
      quantity: 0
    };
  },
  methods: {
    ...mapActions(["sellStock"]),
    sellStock() {
      const order = {
        stockId: this.stock.id,
        stockPrice: this.stock.price,
        quantity: this.quantity
      };
      this.sellStock(order);
      this.quantity = 0;
    }
  }
};
</script>

ما اینجا فقط به یک action نیاز داشتیم بنابراین نیازی نبود که از mapActions استفاده کنیم (می توانستیم به راحتی آن را dispatch کنیم) اما من می خواستم که به شما یادآوری کنم که روش های دیگری نیز برای صدا زدن Action هایمان داریم. با انجام این کار، این فایل (Stock.js در پوشه portfolio) تکمیل شده است و تنها کاری که باقی مانده است رفتن به Portfolio.vue برای نمایش سهام است.

برای نمایش سهام باید به فایل Portfolio.vue می رویم و اول از همه stock های خود را در آن دریافت می کنیم:

<script>
import { mapGetters } from "vuex";
import Stock from "./Stock";

export default {
  computed: {
    ...mapGetters({
      stocks: "stockPortfolio"
    })
  },
  components: {
    appStock: Stock
  }
};
</script>

من در قدم اول mapGetters را صدا زده ام تا بتوانم Getter ای به نام stockPortfolio را صدا بزنم. البته به جای پاس دادن آرایه، یک شیء را به آن پاس داده ام تا بتوانم به نام stocks از آن استفاده کنم. در قدم بعدی Stock.vue را وارد این فایل نموده و آن را به عنوان یک کامپوننت محلی ثبت کرده ام. در مرحله بعد در قسمت template این فایل می گوییم:

<template>
  <div>
    <app-stock v-for="stock in stocks" :stock="stock"></app-stock>
  </div>
</template>

یعنی با v-for بین stocks (از Getter گرفته ایم) گردش می کنم و stock را نیز به عنوان props به app-stock پاس می دهم چرا که اگر یادتان باشد از آن در فایل stock.vue (پوشه portfolio) استفاده می کنیم:

export default {
  props: ["stock"],
  data() {
    return {
      quantity: 0
    };
  },
// بقیه کدها //

برای تست این کدها به صفحه Stocks در مرورگر بروید (آدرس http://localhost:8080/stocks) و چند سهم را از هر شرکتی بخرید. سپس به صفحه Portfolio (آدرس http://localhost:8080/portfolio) بروید و باید سهام خود را در آنجا مشاهده کنید. البته فعلا نمی توانیم چیزی را بفروشیم، چرا؟ به دلیل اینکه در کدهای این جلسه مشکلی وجود دارد. من از عمد قسمتی را به اشتباه نوشته ام. آیا می توانید آن را پیدا کنید؟

در فایل Stock.vue در پوشه portfolio کدی به شکل زیر داریم:

methods: {
  ...mapActions(["sellStock"]),
  sellStock() {
    const order = {
      stockId: this.stock.id,
      stockPrice: this.stock.price,
      quantity: this.quantity
    };
    this.sellStock(order);
    this.quantity = 0;
  }
}

در اینجا نام action من sellStock است و از طرفی نام متد خودم نیز sellStock است بنابراین وقتی متد خودم صدا زده می شود (با کلیک روی دکمه Sell) خودش this.sellStock را دوباره اجرا می کند، بنابراین در یک حلقه نامتناهی گیر می کنیم. برای حل آن می گوییم:

methods: {
  ...mapActions({
    placeSellOrder: "sellStock"
  }),
  sellStock() {
    const order = {
      stockId: this.stock.id,
      stockPrice: this.stock.price,
      quantity: this.quantity
    };
    this.placeSellOrder(order);
    this.quantity = 0;
  }
}

یعنی به راحتی نام action را تغییر داده ایم و حالا می توانید کدها را در مرورگر تست کنید.

visio 2019 lizenz kaufen

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

احمد
22 خرداد 1400
سلام.وقت شما بخیر خسته نباشید من چندبار همین کدهارو در برنامم کپی/پیست کردم ولی بعد از اجرا با این دو ارور مواجه می شوم: [Vue warn]: Property or method "stock" is not defined on the instance but referenced during render و Error in render: "TypeError: Cannot read property 'name' of undefined" لطفا راهنمایی فرمایید.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.