刺激如何从不同子控制器中的值(购物车 - ; CART项目)中计算出父控制器中的值

发布于 2025-02-03 20:21:45 字数 2005 浏览 3 评论 0原文

我正在建造一个用刺激的购物车。购物车摘要页面显示多个购物车项目。购物车物品具有单价和数量。 每个购物车项目组件都有一个数量选择器,当数量数更改Cartitem元素的总价格totalCartitem = uttercartitem = UnitPrice x量,如果还必须重新计算code code code total cartcartcartprice和总价= sum(totalcartitem)

这是对HTML结构的简化

<div class="cart" data-controller='cart'>
  <div class="cart-item" data-controller='cart-item'>
    <p class='unit-price'>20</p>
    <input type="number" name="quantity" value="1">
    <p class='total-price' data-target='cart-item.totalPrice' data-action="change->cart-item#update" data-target='cart-item.quantity'>20</p>
  </div>
  <div class="cart-item" data-controller='cart-item'>
    <p class='unit-price'>10</p>
    <input type="number" name="quantity" value="2" data-action="change->cart-item#update" data-target='cart-item.quantity'>
    <p class='total-price' data-target='cart-item.totalPrice'>20</p>
  </div>
  <div class="cart-total">
    40
  </div>
</div>

我的购物车项目控制器的工作正常,并正确更新了UI中的CART项目的TotalPrice。

export default class extends Controller {
  static targets = ["totalPrice", "quantity"]

  static values = {
    unitPrice: String,
  }

  connect() {
    console.log("hello from StimulusJS")
  }

  update(){
    this.totalPriceTarget.textContent = parseFloat(this.unitPriceValue) * parseInt(this.quantityTarget.value)
  }
}

但是,我现在对如何更新totalcartprice感到迷失。我觉得这应该是cartcontroller包装Cartitems元素的责任,但我不知道正确实现此目的的ID是什么ID。 我觉得我应该在每个编号输入选择器上添加更改 fording ,以适用于每个购物车的数量,但是我应该将什么添加到购物车#更新方法中,以重新计算总计每个购物车物品?

export default class extends Controller {
  static targets = ["total"]
  connect() {
    console.log("hello from StimulusJS")
  }

  update(){
    // let details = event.detail;
    // this.cartItemChildren.forEach((item) => console.log(item.totalValue))
  }
}

I am building a cart with stimulus. The cart recap page displays multiple cart items. A cart item has a unit price and a quantity.
Each cart item component has a quantity selector, when the quantity number changes the total price of the cartitem element is recalculated totalCartItem = unitPrice x Quantity and the total price if the cart must also be recalculated totalCartPrice = sum(totalCartItem)

Here's a simplification of the html structure

<div class="cart" data-controller='cart'>
  <div class="cart-item" data-controller='cart-item'>
    <p class='unit-price'>20</p>
    <input type="number" name="quantity" value="1">
    <p class='total-price' data-target='cart-item.totalPrice' data-action="change->cart-item#update" data-target='cart-item.quantity'>20</p>
  </div>
  <div class="cart-item" data-controller='cart-item'>
    <p class='unit-price'>10</p>
    <input type="number" name="quantity" value="2" data-action="change->cart-item#update" data-target='cart-item.quantity'>
    <p class='total-price' data-target='cart-item.totalPrice'>20</p>
  </div>
  <div class="cart-total">
    40
  </div>
</div>

My cart item controller works perfectly fine and updates correctly the totalPriceFor a cart item in the UI.

export default class extends Controller {
  static targets = ["totalPrice", "quantity"]

  static values = {
    unitPrice: String,
  }

  connect() {
    console.log("hello from StimulusJS")
  }

  update(){
    this.totalPriceTarget.textContent = parseFloat(this.unitPriceValue) * parseInt(this.quantityTarget.value)
  }
}

However, I am now lost on how to update the totalCartPrice. I feel like this should be the responsability of the cartController that wrapps the cartItems elements, but I have no idea on what id the correct way to achieve this.
I feel like I should add change->cart#update on each number input selector for quantity for each cart-item, but then what should I add to the cart#update method to recalculate the total from each individual cart item ?

export default class extends Controller {
  static targets = ["total"]
  connect() {
    console.log("hello from StimulusJS")
  }

  update(){
    // let details = event.detail;
    // this.cartItemChildren.forEach((item) => console.log(item.totalValue))
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南渊 2025-02-10 20:21:45

根据刺激文档,始终最好开始使用HTML 。通过扩展,最好以可访问的方式构建HTML,并查看浏览器为您提供的东西而不重新发明内容。

当您构建表单时,即使没有提交此表单,也最好使用表单元素。 https://developer.mozilla.orgg/en-us/docs/ Web/api/htmlformelement

还有一个非常有用的输出元素,可以帮助您根据某些输入值分配输出值。 https://develoverer.mozilla.org/ en-us/doc/web/html/element/umput#attr-for

最后,形式元素有一个DOM API,可让您通过其name name 属性,这是form.elementshttps:// https://developer.mozilla.org/en-us/ docs/web/api/htmlformelement/elements

将其结合在一起,我们可以从以下HTML开始...

html

  • 我们只是将我们的控制器操作附加到整个表单上,因此我们可以聆听任何更改的更改表格中的输入。
  • 一个用于这种情况的控制器,而文档推荐较小的粒状控制器,但这里最小的单位内容似乎是整个形式。
  • 每个输入都有一个唯一的ID,每个输出元素引用使用此ID的输入使用 for 属性 - 这将更好当我们想解析值并更新输出时,请用方便。
  • 我们还具有使用相同ID的单位价格的其他数据属性,请注意,此数据属性并不特别,但只给了我们一种“查找”相关价格的方法。无需为这种简单情况创建控制器目标。
  • 注意:这是假设您不必支持IE11(因为输出元素在该浏览器中不起作用)。
<form class="cart" data-controller='cart' data-action="change->cart#updateTotals">
  <div class="cart-item">
    <span class='unit-price' data-price-for="cart-item-1">20</span>
    x
    <input type="number" name="quantity" value="1" id="cart-item-1">
    =
    <output class="total-price" for="cart-item-1" name="item-total">20</output>
  </div>
  <div class="cart-item">
    <span class='unit-price' data-price-for="cart-item-2">10</span>
    x
    <input type="number" name="quantity" value="1" id="cart-item-2">
    =
    <output class="total-price" for="cart-item-2" name="item-total">10</output>
  </div>
  <div class="cart-total">
    Total: <span data-cart-target="total">30</span>
  </div>
</form>

JavaScript(控制器)

  • 我们的控制器除了总的总目标外,实际上并不需要其他任何东西,因为我们可以在基本表单的附件控制器上使用this.Element
  • 我们避免使用通用更新方法,并尝试使用updateTotals更具体。
  • 我们在表单上使用elements api,以获取具有名称'item-total'的元素(请注意,输出名称未提交)。 https:// https://developer.mozilla.org/en-us/ doc/web/api/htmlformelement/elements
  • 一旦拥有每个输出元素,我们就可以通过和输入的ID找到相关的输入元素,然后找到数据属性以找到价格。
  • 然后,我们计算一个宏伟的总数,最后更新DOM中的所有值。
  • 注意:数字解析非常基本,最好在这里添加一些安全性,也假设您不需要支持IE11。
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
  static targets = ['total'];

  connect() {
    this.updateTotals();
  }

  updateTotals() {
    // parse the form elements to get all data
    // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements

    const cartItems = [...this.element.elements['item-total']].map(
      (outputElement) => {
        const forId = outputElement.getAttribute('for');
        const priceElement = document.querySelector(`[data-price-for='${forId}']`);
        const price = Number(priceElement.textContent);
        const quantity = Number(document.getElementById(forId).value);
        return { outputElement, total: quantity * price };
      }
    );

    // calculate the grand total
    const grandTotal = cartItems.reduce(
      (runningTotal, { total }) => runningTotal + total,
      0
    );

    // update the grand total
    this.totalTarget.textContent = grandTotal;

    // update totals for each cart item
    cartItems.forEach(({ outputElement, total }) => {
      outputElement.textContent = total;
    });

    console.log('form updated', { grandTotal, cartItems });
  }
}

As per the Stimulus documentation, it is always best to start with the HTML. By extension it is best to structure your HTML in an accessible way and see what the browser gives you without reinventing things.

When you are building forms, it is best to use the form element, even if this form is not being submitted. https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement

There is also a very useful output element that helps you assign an output value based on some input value. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output#attr-for

Finally, there is a DOM API for the form element that lets you access various parts of the form via their name attribute, this is form.elements. https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements

Bringing this together we can start with the following HTML...

HTML

  • We are simply attaching our controller action to the form as a whole, so we can listen to any change to the inputs within the form.
  • One controller for this case, while the docs to recommend smaller granular controllers, the smallest unit content here appears to be the form as a whole.
  • Each input has a unique ID and each output element references the input via this id using the for attribute - this will be better for accessibility but comes in handy when we want to parse the values and update outputs.
  • We also have an additional data attribute on the unit price that uses the same id, note that this data attribute is nothing special but just gives us a way to 'find' the relevant price. No need to create a controller target for this simple case.
  • Note: This assumes you do not have to support IE11 (as the output element will not work in that browser).
<form class="cart" data-controller='cart' data-action="change->cart#updateTotals">
  <div class="cart-item">
    <span class='unit-price' data-price-for="cart-item-1">20</span>
    x
    <input type="number" name="quantity" value="1" id="cart-item-1">
    =
    <output class="total-price" for="cart-item-1" name="item-total">20</output>
  </div>
  <div class="cart-item">
    <span class='unit-price' data-price-for="cart-item-2">10</span>
    x
    <input type="number" name="quantity" value="1" id="cart-item-2">
    =
    <output class="total-price" for="cart-item-2" name="item-total">10</output>
  </div>
  <div class="cart-total">
    Total: <span data-cart-target="total">30</span>
  </div>
</form>

JavaScript (Controller)

  • Our controller does not really need anything other than the grand total target, as we can use this.element on the base form's attached controller.
  • We are avoiding a generic update method and trying to be more specific with updateTotals.
  • We use the elements API on the form to get the elements with the name 'item-total' (note that output names do not get submitted). https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
  • Once we have each output element, we can find the relevant input element via the for and the input's id and then the data attribute to find the price.
  • We then calculate a grand total and finally update all the values in the DOM.
  • Note: Number parsing is very basic, best to add some safety here, also we are assuming you do not need to support IE11.
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
  static targets = ['total'];

  connect() {
    this.updateTotals();
  }

  updateTotals() {
    // parse the form elements to get all data
    // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements

    const cartItems = [...this.element.elements['item-total']].map(
      (outputElement) => {
        const forId = outputElement.getAttribute('for');
        const priceElement = document.querySelector(`[data-price-for='${forId}']`);
        const price = Number(priceElement.textContent);
        const quantity = Number(document.getElementById(forId).value);
        return { outputElement, total: quantity * price };
      }
    );

    // calculate the grand total
    const grandTotal = cartItems.reduce(
      (runningTotal, { total }) => runningTotal + total,
      0
    );

    // update the grand total
    this.totalTarget.textContent = grandTotal;

    // update totals for each cart item
    cartItems.forEach(({ outputElement, total }) => {
      outputElement.textContent = total;
    });

    console.log('form updated', { grandTotal, cartItems });
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文