按具体分组并计算动态添加的对象的总数Angular 2

时间:2018-06-24 19:56:34

标签: javascript angular

我在Angular 2中有一个表单,其中包含由用户动态添加的字段。添加的对象如下所示:

[ { "equipment_type_id": 1, "action": "added", "quantity": 3}]

设备类型可以重复使用不同的数量,我需要按equipment_type_id分组并使用数量计算总数。

我已经使用了reduce函数进行分组,但不确定如何计算总数而不是仅仅将数量添加到新对象中

var groups = this.inspection.equipments.reduce(function(obj,item){
  obj[item.equipment_type_id] = obj[item.equipment_type_id] || [];
  obj[item.equipment_type_id].push(item.quantity);
  return obj;
}, {});

任何帮助都会很棒

2 个答案:

答案 0 :(得分:0)

首先,您需要检查是否已添加该类型的项目:

<html><head>
    <meta charset="utf-8">
    <meta content="IE=edge" http-equiv="X-UA-Compatible">
    <meta content="width=device-width,initial-scale=1.0" name="viewport">
       <title>Reset password</title>
<style type="text/css">    
html
{
  box-sizing: border-box;
  line-height: 1.15;
}
*,
*::before,
*::after
{
  box-sizing: inherit;
}
body
{
  margin: 0;
  font-family:
    'Segoe UI',
    Roboto,
    Helvetica,
    Arial,
    sans-serif;
}
h1
{
  font-size: 2em;
  margin: 0.67em 0;
}
hr
{
  height: 0;
}
abbr[title]
{
          text-decoration: underline dotted;
}
b,
strong
{
  font-weight: bolder;
}
code,
kbd,
samp,
pre
{
  font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; /* 1 */
  font-size: 1em; /* 2 */
}
small
{
  font-size: 80%;
}
sub,
sup
{
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}
sub
{
  bottom: -0.25em;
}
sup
{
  top: -0.5em;
}
button,
input,
optgroup,
select,
textarea
{
  font-family: inherit; /* 1 */
  font-size: 100%; /* 1 */
  line-height: 1.15; /* 1 */
  margin: 0; /* 2 */
}
button,
select
{
  text-transform: none;
}
button,
[type='button'],
[type='reset'],
[type='submit']
{
  -webkit-appearance: button;
}
button::-moz-focus-inner,
[type='button']::-moz-focus-inner,
[type='reset']::-moz-focus-inner,
[type='submit']::-moz-focus-inner
{
  border-style: none;
  padding: 0;
}
button:-moz-focusring,
[type='button']:-moz-focusring,
[type='reset']:-moz-focusring,
[type='submit']:-moz-focusring
{
  outline: 1px dotted ButtonText;
}
fieldset
{
  padding: 0.35em 0.75em 0.625em;
}
legend
{
  padding: 0;
}
progress
{
  vertical-align: baseline;
}
[type='number']::-webkit-inner-spin-button,
[type='number']::-webkit-outer-spin-button
{
  height: auto;
}
[type='search']
{
  -webkit-appearance: textfield; /* 1 */
  outline-offset: -2px; /* 2 */
}
[type='search']::-webkit-search-decoration
{
  -webkit-appearance: none;
}
::-webkit-file-upload-button
{
  -webkit-appearance: button; /* 1 */
  font: inherit; /* 2 */
}
:root
{
     tab-size: 4;
}
details
{
  display: block;
}
summary
{
  display: list-item;
}
h1, h2, h3, h4, h5, h6
{
  font-weight: 400;
}
p, ul, ol
{
  margin: 0.25rem 0;
}
h1
{
  margin: 1.5rem 0;
  font-size: 2rem;
  line-height: 1.25;
}
h2
{
  margin: 1.2rem 0;
  font-size: 1.75rem;
  line-height: 1.15384615;
}
h3
{
  margin: 1rem 0;
  font-size: 1.5rem;
  line-height: 1.13636364;
}
h4
{
  margin: 0.8rem 0;
  font-size: 1.375rem;
  line-height: 1.11111111;
}
h5
{
  margin: 0.65rem 0;
  font-size: 1.125rem;
  line-height: 1;
}
blockquote
{
  font-size: 1.25em;
  line-height: 1.25;
}
@media (min-width: 43.75em)
{
h1
  {
    font-size: 2.5em;
    line-height: 1.125;
}
h2
  {
    font-size: 2em;
    line-height: 1.25;
}
h3
  {
    font-size: 1.5em;
    line-height: 1.25;
}
h4
  {
    line-height: 1.22222222;
}
blockquote
  {
    font-size: 1.5em;
    line-height: 1.45833333;
}
}
@media (min-width: 56.25em)
{
h1
  {
    font-size: 3em;
    line-height: 1.05;
}
h2
  {
    font-size: 2.25em;
    line-height: 1.25;
}
h3
  {
    font-size: 1.75em;
    line-height: 1.25;
}
}
.bold
{
  font-weight: bold;
}
.btn
{
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  border: none;
  border-radius: 6px;
  padding: 0.5rem 1rem 0.35rem;
  box-shadow: inset 0 0 0 1px #27496D;
}
.btn:not([disabled]):hover
{
  box-shadow: inset 0 0 0 1px #27496D, 0 5px 15px #193047;
}
.btn:not([disabled]):active
{
          transform: translate(1px, 1px);
  box-shadow: inset 0 0 0 1px #27496D, inset 0 5px 30px #193047;
}
.btn_yes
{
  background-color: #6CBA30;
  color: white;
}
.btn_no
{
  background-color: #ED5B44;
  color: white;
}
.btn_dark
{
  background-color: #34495E;
  color: white;
}
.btn_edit
{
  background-color: #F27935;
  color: white;
}
.btn_primary
{
  background-color: #03A9F4;
  color: white;
}
a
{
  color: #008840;
}
input,
select
{
  border: 1px solid #A9A9A9;
  border-radius: 2px;
  padding: 2px 4px;
}
svg
{
  vertical-align: middle;
}
*[disabled]
{
  opacity: 0.6;
  cursor: not-allowed;
}
textarea
{
  background-color: #FFFFE0;
}
input:valid
{
  border: 1px solid #3EAF7C;
}
input:invalid
{
  border: 1px solid #EC407A;
}
input:focus
{
  outline: none;
  border: 1px solid #3477C9;
}
input[type=date]
{
  width: 8rem;
  padding: 2px 0 2px 4px;
}
input[type=date]::-webkit-inner-spin-button,
input[type=date]::-webkit-clear-button,
input[type=date]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button
{
  -webkit-appearance: none;
}
.vue-loading
{
  position: absolute;
  top: 0;
  left: 0;
  z-index: 120;
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  border: none;
  background-color: rgba(230, 233, 236, 0.8);
  cursor: wait;
  opacity: 0;
  -o-transition: opacity 0.4s;
  transition: opacity 0.4s;
  display: -webkit-flex;
  display: flex;
          justify-content: center;
          align-items: center;
}
.vue-loading > *
{
          animation: rot 1.1s infinite linear;
}
@-webkit-keyframes rot
{
0%
  {
            transform: rotate(0deg);
}
100%
  {
            transform: rotate(359deg);
}
}
@-o-keyframes rot
{
0%
  {
       transform: rotate(0deg);
}
100%
  {
       transform: rotate(359deg);
}
}
@keyframes rot
{
0%
  {
            transform: rotate(0deg);
}
100%
  {
            transform: rotate(359deg);
}
}
#app
{
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
}
.login_modal
{
  padding: 20px 25px;
}
.help_reset
{
  color: #999;
  padding-left: 1.85rem;
}

.home
{
  height: 100vh;
  overflow: hidden;
  display: flex;
          flex-direction: column;
}
.home_header
{
  text-align: center;
  background-color: #F27935;
  color: white;
  margin: 0;
  padding: 0.8rem;
}
.home_learn
{
  display: -webkit-flex;
  display: flex;
  -webkit-justify-content: center;
          justify-content: center;
  margin-top: 20px;
  padding: 0 20px;
}
.home_link
{
  display: inline-block;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  color: white;
  background-color: #3EAF7C;
  padding: 0.75rem 1.2rem;
  margin: 1rem 1.5rem;
  border-radius: 2rem;
  letter-spacing: 0.85px;
}
.home_link:hover
{
  box-shadow: inset 0 0 0 1px #46BD87, 0 3px 10px #193047;
}
.home_link:active
{
          transform: translate(1px, 1px);
  box-shadow: inset 0 0 0 1px #46BD87, inset 0 5px 12px #193047;
}
.home_body
{
          flex: 1 1 auto;
  display: flex;
          justify-content: center;
          align-items: center;
  overflow: auto;
}
.login_panel
{
  margin: 20px 25px;
}
@media screen and (max-width: 450px)
{
.home_learn
  {
            justify-content: space-around;
            flex-wrap: wrap;
}
}
@media screen and (min-width: 480px)
{
.home_learn > * + *
  {
    margin-left: 60px;
}
}

.home_card
{
  margin: 20px;
  border-radius: 2px;
  box-shadow:
    0 2px 1px -1px rgba(0, 0, 0, 0.2),
    0 1px 1px 0 rgba(0, 0, 0, 0.2),
    0 1px 5px 0 rgba(0, 0, 0, 0.16);
          transform-origin: 50% 0;
          animation: form-fly-up 1.3s linear;
}
.home_card--header
{
  line-height: 1.5;
  margin: 0;
  padding: 0 8px;
  color: white;
  background-color: #BA68C8;
  text-align: center;
}
.home_card--body
{
  position: relative;
  overflow: hidden;
}
.button_bounce
{
          animation: button-bounce 1s 0.12s linear;
}
.login_bar
{
  display: flex;
          justify-content: space-around;
  margin: 25px 0;
}
.login_separator
{
  display: flex;
}
.login_separator > div
{
          flex: 1 1 100%;
  padding: 0 8px;
}
@keyframes form-fly-up
{
0% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 500, 0, 1);
}
1.69% {  transform: matrix3d(1, 0, 0, 0, 0, 1.351, 0, 0, 0, 0, 1, 0, 0, 330.533, 0, 1);
}
3.18% {  transform: matrix3d(1, 0, 0, 0, 0, 1.431, 0, 0, 0, 0, 1, 0, 0, 209.854, 0, 1);
}
3.32% {  transform: matrix3d(1, 0, 0, 0, 0, 1.431, 0, 0, 0, 0, 1, 0, 0, 200.398, 0, 1);
}
6.29% {  transform: matrix3d(1, 0, 0, 0, 0, 1.306, 0, 0, 0, 0, 1, 0, 0, 52.745, 0, 1);
}
6.88% {  transform: matrix3d(1, 0, 0, 0, 0, 1.27, 0, 0, 0, 0, 1, 0, 0, 35.081, 0, 1);
}
6.98% {  transform: matrix3d(1, 0, 0, 0, 0, 1.263, 0, 0, 0, 0, 1, 0, 0, 32.413, 0, 1);
}
6.98% {  transform: matrix3d(1, 0, 0, 0, 0, 1.263, 0, 0, 0, 0, 1, 0, 0, 32.23, 0, 1);
}
8.93% {  transform: matrix3d(1.056, 0, 0, 0, 0, 1.101, 0, 0, 0, 0, 1, 0, 0, -4.194, 0, 1);
}
9.39% {  transform: matrix3d(1.066, 0, 0, 0, 0, 1.07, 0, 0, 0, 0, 1, 0, 0, -9.217, 0, 1);
}
10.59% { transform: matrix3d(1.087, 0, 0, 0, 0, 1.005, 0, 0, 0, 0, 1, 0, 0, -17.779, 0, 1);
}
10.79% { transform: matrix3d(1.09, 0, 0, 0, 0, 0.996, 0, 0, 0, 0, 1, 0, 0, -18.669, 0, 1);
}
12.49% { transform: matrix3d(1.108, 0, 0, 0, 0, 0.94, 0, 0, 0, 0, 1, 0, 0, -21.678, 0, 1);
}
14.26% { transform: matrix3d(1.115, 0, 0, 0, 0, 0.91, 0, 0, 0, 0, 1, 0, 0, -19.497, 0, 1);
}
14.61% {transform: matrix3d(1.115, 0, 0, 0, 0, 0.907, 0, 0, 0, 0, 1, 0, 0, -18.72, 0, 1);
}
17.59% { transform: matrix3d(1.104, 0, 0, 0, 0, 0.906, 0, 0, 0, 0, 1, 0, 0, -11.021, 0, 1);
}
17.87% { transform: matrix3d(1.102, 0, 0, 0, 0, 0.908, 0, 0, 0, 0, 1, 0, 0, -10.337, 0, 1);
}
20.48% {transform: matrix3d(1.08, 0, 0, 0, 0, 0.928, 0, 0, 0, 0, 1, 0, 0, -4.9, 0, 1);
}
21.11% { transform: matrix3d(1.074, 0, 0, 0, 0, 0.933, 0, 0, 0, 0, 1, 0, 0, -3.919, 0, 1);
}
26.25% { transform: matrix3d(1.027, 0, 0, 0, 0, 0.978, 0, 0, 0, 0, 1, 0, 0, 0.127, 0, 1);
}
29.72% {transform: matrix3d(1.003, 0, 0, 0, 0, 0.998, 0, 0, 0, 0, 1, 0, 0, 0.518, 0, 1);
}
32.12% {transform: matrix3d(0.992, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0.432, 0, 1);
}
32.42% { transform: matrix3d(0.991, 0, 0, 0, 0, 1.008, 0, 0, 0, 0, 1, 0, 0, 0.414, 0, 1);
}
37.89% { transform: matrix3d(0.983, 0, 0, 0, 0, 1.014, 0, 0, 0, 0, 1, 0, 0, 0.11, 0, 1);
}
46.95% {transform: matrix3d(0.993, 0, 0, 0, 0, 1.006, 0, 0, 0, 0, 1, 0, 0, -0.012, 0, 1);
}
46.97% {transform: matrix3d(0.993, 0, 0, 0, 0, 1.006, 0, 0, 0, 0, 1, 0, 0, -0.012, 0, 1);
}
49.53% {transform: matrix3d(0.996, 0, 0, 0, 0, 1.003, 0, 0, 0, 0, 1, 0, 0, -0.01, 0, 1);
}
58.14% {transform: matrix3d(1.002, 0, 0, 0, 0, 0.998, 0, 0, 0, 0, 1, 0, 0, -0.001, 0, 1);
}
61.17% {transform: matrix3d(1.003, 0, 0, 0, 0, 0.998, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
64.17% {transform: matrix3d(1.002, 0, 0, 0, 0, 0.998, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
77.52% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
84.45% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
100% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
}
@keyframes button-bounce
{
0% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
2.1% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -6.676, 0, 1);
}
4.1% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -10.831, 0, 1);
}
8.21% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -13.795, 0, 1);
}
11.41% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -12.485, 0, 1);
}
14.51% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -9.638, 0, 1);
}
20.72% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -3.182, 0, 1);
}
27.03% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0.969, 0, 1);
}
33.23% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2.063, 0, 1);
}
45.75% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0.472, 0, 1);
}
58.26% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -0.309, 0, 1);
}
83.28% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0.046, 0, 1);
}
100% {transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
}     
.form_field
{
  margin: 8px;
}
.form_field > *
{
  display: block;
}
.form_field > label
{
  margin-bottom: 6px;
}
.field_error
{
  font-family: 'Segoe UI', Tahoma, sans-serif;
  font-size: 85%;
  color: red;
  margin: 3px 0;
}

.VuePassword
{
  position: relative;
}
.VuePassword__Input
{
  position: relative;
}
.VuePassword input
{
  padding-right: 2.5em;
  width: 100%;
}
.VuePassword__Toggle
{
  color: gray;
  display: inline-block;
  height: 100%;
  position: absolute;
  right: 0;
  top: 0;
  z-index: 1;
  cursor: pointer;
}
.VuePassword__Toggle__Icon
{
  fill: currentColor;
  height: 100%;
  width: 1.5em;
  margin-right: 0.5em;
          user-select: none;
}
.VuePassword__Meter
{
  color: rgb(175, 175, 175);
  display: block;
  height: 0.5rem;
  margin-top: 0.2rem;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  width: 100%;
}
.VuePassword__Meter path
{
  stroke: currentColor;
  stroke-width: 2;
}
.VuePassword--very-weak
{
  color: rgb(175, 175, 175);
}
.VuePassword--weak
{
  color: rgb(230, 30, 30);
}
.VuePassword--medium
{
  color: rgb(255, 160, 65);
}
.VuePassword--good
{
  color: rgb(100, 200, 75);
}
.VuePassword--great
{
  color: rgb(75, 150, 50);
}
.VuePassword__Message
{
  cursor: default;
  font-size: 1rem;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  text-align: right;
  text-transform: uppercase;
}
</style>
</head>
  <body>
  <div id="app">
    <div class="home">
      <div>some text</div>
      <div>some text</div>
      <div>some text</div>      
      <div class="home_body">
        <div class="home_card">
          <h3 class="home_card--header">Reset password</h3>
          <div class="home_card--body">
            <form class="login_panel">
              <h4>What is a good password ?</h4>
              <ul>
                <li>composed of multiple meaningless words</li>
                <li>contains mixed-case letters</li>
                <li>left + right padded with non-alphabet symbols</li>
                <li>just make it longer &ndash; 20‐30 symbols and up</li>
              </ul>
              <div align="center">
                <a class="home_link" href="https://www.grc.com/haystack.htm" target="_blank">TIPS + HINTS</a>
              </div>
              <div class="form_field">
                <label for="inp5">Enter a new password</label>
                <div class="VuePassword">
                  <div class="VuePassword__Input">
                    <input class="form-control" maxlength="100" required="required" type="password"> <a class="VuePassword__Toggle" role="button"><svg class="VuePassword__Toggle__Icon" viewbox="0 0 32 32">
                    <path d="M16 6c-6.979 0-13.028 4.064-16 10 2.972 5.936 9.021 10 16 10s13.027-4.064 16-10c-2.972-5.936-9.021-10-16-10zM23.889 11.303c1.88 1.199 3.473 2.805 4.67 4.697-1.197 1.891-2.79 3.498-4.67 4.697-2.362 1.507-5.090 2.303-7.889 2.303s-5.527-0.796-7.889-2.303c-1.88-1.199-3.473-2.805-4.67-4.697 1.197-1.891 2.79-3.498 4.67-4.697 0.122-0.078 0.246-0.154 0.371-0.228-0.311 0.854-0.482 1.776-0.482 2.737 0 4.418 3.582 8 8 8s8-3.582 8-8c0-0.962-0.17-1.883-0.482-2.737 0.124 0.074 0.248 0.15 0.371 0.228v0zM16 13c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3z"></path></svg> <!----></a>
                  </div><svg class="VuePassword__Meter" preserveaspectratio="none" viewbox="0 0 123 2">
                  <path class d="M0 1 L30 1"></path>
                  <path class d="M31 1 L61 1"></path>
                  <path class d="M62 1 L92 1"></path>
                  <path class d="M93 1 L123 1"></path></svg>
                  <div class="VuePassword__Message VuePassword--very-weak"></div>
                </div>
              </div>
              <div class="form_field">
                <label for="inp7">Retype the password</label> <input maxlength="100" required="required" style="width: 100%;" type="password">
                <div class="field_error"></div>
              </div>
              <ul class="help_reset">
                <li>password is case-sensitive</li>
                <li>max length is 100 symbols</li>
                <li>leading / trailing whitespace will be trimmed</li>
              </ul>
              <div class="login_bar">
                <button class="btn btn_primary" type="submit">SUBMIT</button>
              </div>
              <div class="login_bar">
                <button class="btn btn_dark" type="button">Back to Login</button>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
</body></html>

如果有(即上述if语句为假),则只需添加新数量:

if (obj[item.equipment_type_id] == null)

下面是一个例子

obj[item.equipment_type_id].quantity += item.quantity;

答案 1 :(得分:0)

使用以下方法解决了此问题:

calcTotals(){
    var groups = this.inspection.equipments.reduce(function(obj,item){
      obj[item.equipment_type_id] = obj[item.equipment_type_id] || { equipment_type_id: item.equipment_type_id, total: 0};
      // Calculate total based on action
      var total = obj[item.equipment_type_id].total;
      if(item.action === 'added'){
        total = total + item.quantity;
      }else{
        total = total - item.quantity;
      };
      obj[item.equipment_type_id].total = total;
      return obj;
    }, {});
    return groups;
}