Home > Software design >  Check if inputs filled before dynamically append another row
Check if inputs filled before dynamically append another row

Time:01-23

enter image description here

I have ADD button, when I clicked it, I added a row. I want to add a restriction, if only if row 2 is filled, then row 3 will be displayed. If 3 are filled, then 4 will be displayed, you get the idea...

I'ved tried something, but I don't think I am in the right track.

// console.log('rule',rule)

// if(rule.attribute.name != '' && rule.operator != '' && rule.value != ''){
//  this.rules.push(rule)
// }

Right now, it endless appending...

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script><link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">


<template id="mainbox">
    <v-card outlined >
        <v-list-item three-line>
            <v-list-item-content>
                <div >

                    {{ title }}
                </div>
                <v-container>
                    <!-- -------------------------------------------------------------------------- -->
                    <v-divider></v-divider>
                    <!-- -------------------------------------------------------------------------- -->
                    <!-- TEST CODE -->
                    <!-- --------- -->




                    <v-col cols="12">
                        <v-btn color="primary" outlined @click="addRule()"> Add </v-btn>
                    </v-col>



                    <v-row v-for="(rule, index) in rules" :key="rule.id">

                        <v-col cols="4">
                            <v-select dense outlined item-text="name" :items="attributes" item-value="id" v-model="rule.attribute.id" label="Attribute"></v-select>
                        </v-col>

                        <v-col cols="4">
                            <v-combobox v-model="rule.operator" :items="operators" item-text="operator" item-value="id" label="Operator" outlined dense></v-combobox>
                        </v-col>

                        <v-col cols="4">
                            <v-text-field v-model="rule.value" :items="values" label="Value" multiple outlined dense></v-text-field>
                        </v-col>
                    </v-row>



                    <!-- -------------------------------------------------------------------------- -->
                    <v-divider></v-divider>
                    <!-- -------------------------------------------------------------------------- -->
                    <!-- LIVE VALUE -->
                    <!-- --------- -->


                    <v-alert
                    outlined
                    type="success"
                    text
                    >
                    <b>this.rules :</b>  {{ rules }}
                </v-alert>




            </v-container>
        </v-list-item-content>
    </v-list-item>
</v-card>
</template>


<v-app id="app">


    <!-- -------------------------------------------------------------------------- -->
    <!-- TITLE -->
    <!-- ----- -->



    <mainbox title="$CODE_08" />


    <!-- -------------------------------------------------------------------------- -->


</v-app>

<script type="text/javascript">

    const mainbox = Vue.component('mainbox', {
        template: '#mainbox',
        props: { title: String },
        data() {
            return {
                rules: [
                
                {
                    attribute: {
                        name: 'Style name',
                        id: 3
                    },
                    operator: '=',
                    value: '123'
                }

                ],
                operators: ['=', '!='],
                values: ['China', 'US', ' Thai'],
                attributes : [ { "id": 1, "name": "Style name", "alias": null, "attribute": "STYLE_NAME", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 2, "name": "Country", "alias": null, "attribute": "COUNTRY_NAME", "category_id": 2, "data_type_id": 3, "data_type_name": "String" }, { "id": 3, "name": "Serial number", "alias": null, "attribute": "scanstring", "category_id": 3, "data_type_id": 3, "data_type_name": "String" }, { "id": 4, "name": "Brand Name", "alias": null, "attribute": "BRAND_NAME", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 5, "name": "Account/Customer Name", "alias": null, "attribute": "CUSTOMER_NAME", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 6, "name": "Product UPC", "alias": null, "attribute": "PRODUCT_UPC", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 7, "name": "Label batch", "alias": null, "attribute": "LABEL_HEADER_ID", "category_id": 3, "data_type_id": 1, "data_type_name": "Number" }, { "id": 8, "name": "Current time", "alias": null, "attribute": "time(convert_tz(now(),'UTC','${PARAM}'))", "category_id": 4, "data_type_id": 5, "data_type_name": "Time" } ]

            }
        },
        methods: {
            addRule() {
                console.log('addRule clicked')
                let rule = {
                    attribute: {
                        name: '',
                        id: 0
                    },
                    operator: '',
                    value: ''
                }

                // console.log('rule',rule)

                // if(rule.attribute.name != '' && rule.operator != '' && rule.value != ''){
                //  this.rules.push(rule)
                // }


                this.rules.push(rule)
            }
        }
    });


    new Vue({ el:"#app", vuetify: new Vuetify(), components: { mainbox } });

</script>

CodePudding user response:

Modify the following for your needs, but it should give you a start:

<!DOCTYPE html>
<html>
<!-- From: https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_table_insert_deleterow 
      For: https://stackoverflow.com/questions/70809292/check-if-inputs-filled-before-dynamically-append-another-row 
-->
<head>
<style>
 td { border: 1px solid black; }
</style>
</head>
<body>

<p>Click the buttons to create and delete row(s) for the table.</p>

<button onclick="myCreateFunction()">Create row</button>
<button onclick="myDeleteFunction()">Optional Delete row</button>
<p/>

<table id="myTable">
  <tr> <!-- filled with values for testing purposes only -->
    <td><input type="text" value="Row1 cell1"></td>
    <td><input type="text" value="Row1 cell2"></td>
    <td><input type="text" value="Row1 cell3"></td>
  </tr>
</table>
<br>

<script>
const insertHTMLAfter = (html, el) => el.insertAdjacentHTML('beforeend', html);

function myCreateFunction() {
  let tbodyRef = document.getElementById('myTable').getElementsByTagName('tbody')[0],
      lastRow = tbodyRef.rows.length-1;

  const sel = document.querySelectorAll('#myTable input');  // alert(sel.length);
  let cell1 = sel[lastRow*3 0].value,
      cell2 = sel[lastRow*3 1].value,
      cell3 = sel[lastRow*3 2].value;                       // alert(cell1  ', '  cell2  ', '  cell3);

  if ( (cell1 != '') && (cell2 != '') ) {                   // optional check of cell3 possible here
    lastRow  = 2;
    insertHTMLAfter(  
`  <tr>
    <td><input type="text" value=""></td>
    <td><input type="text" value=""></td>
    <td><input type="text" value=""></td>
  </tr>
`, tbodyRef);
  }
}

// optional function
function myDeleteFunction() {
  var tbodyRef = document.getElementById('myTable').getElementsByTagName('tbody')[0];
  lastRow = tbodyRef.rows.length;
  document.getElementById("myTable").deleteRow(lastRow-1);
}
</script>

</body>
</html>

CodePudding user response:

addRule() {
    console.log('addRule clicked')
    let newRule = {
        attribute: {
            name: '',
            id: 0
        },
        operator: '',
        value: ''
    }

    const lastRule = this.rules.at(-1)
    if (!lastRule || lastRule.attribute.name != '' && lastRule.operator != '' && lastRule.value != '') {
        this.rules.push(newRule)
    }
}

CodePudding user response:

You can split your components and then check if one is empty, check following snippet pls :

const parent = Vue.component('parent', {
  template: '#parent',
  props: { title: String },
  data() {
    return {
      rules: [{ attribute: { name: 'Style name', id: 3 }, operator: '=', value: '123' } ],
      empty: false
    }
  },
  methods: {
    addRule() {
      this.empty = false
      if (this.rules.find(r => r.attribute.name === '' || r.operator === '' || r.value.length === 0)) {
        this.empty = true
      } else {
        let rule = {
          attribute: { name: '', id: 0 },
          operator: '',
          value: ''
        }
        this.rules.push(rule)
      }   
    },
    removeRule(i) {
      this.rules.splice(i, 1)
    }
  }
})
const mainbox = Vue.component('mainbox', {
  template: '#mainbox',
  props: { ruleProp: Object, idx: Number },
  data() {
    return {
      rule: this.ruleProp,
      operators: ['=', '!='],
      values: ['China', 'US', ' Thai'],
      attributes : [ { "id": 1, "name": "Style name", "alias": null, "attribute": "STYLE_NAME", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 2, "name": "Country", "alias": null, "attribute": "COUNTRY_NAME", "category_id": 2, "data_type_id": 3, "data_type_name": "String" }, { "id": 3, "name": "Serial number", "alias": null, "attribute": "scanstring", "category_id": 3, "data_type_id": 3, "data_type_name": "String" }, { "id": 4, "name": "Brand Name", "alias": null, "attribute": "BRAND_NAME", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 5, "name": "Account/Customer Name", "alias": null, "attribute": "CUSTOMER_NAME", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 6, "name": "Product UPC", "alias": null, "attribute": "PRODUCT_UPC", "category_id": 1, "data_type_id": 3, "data_type_name": "String" }, { "id": 7, "name": "Label batch", "alias": null, "attribute": "LABEL_HEADER_ID", "category_id": 3, "data_type_id": 1, "data_type_name": "Number" }, { "id": 8, "name": "Current time", "alias": null, "attribute": "time(convert_tz(now(),'UTC','${PARAM}'))", "category_id": 4, "data_type_id": 5, "data_type_name": "Time" } ]
      }
  },
});

new Vue({ el:"#app", vuetify: new Vuetify(), components: { parent, mainbox } });
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script><link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">

<template id="mainbox">
  <v-container>
    <v-row>
      <v-col cols="3">
        <v-select dense outlined item-text="name" :items="attributes" item-value="id" v-model="rule.attribute.id" label="Attribute"></v-select>
      </v-col>
      <v-col cols="3">
        <v-combobox v-model="rule.operator" :items="operators" item-text="operator" item-value="id" label="Operator" outlined dense></v-combobox>
      </v-col>
      <v-col cols="3">
        <v-text-field v-model="rule.value" :items="values" label="Value" multiple outlined dense></v-text-field>
      </v-col>
      <v-col cols="3">
        <v-btn color="error" outlined @click="$emit('remove', idx)"> Remove </v-btn>
      </v-col>
    </v-row>
  </v-container>
</template>

<template id="parent">
  <v-card outlined >
    <div >
        {{ title }}
    </div>
    <v-list-item three-line>
      <v-list-item-content>
        <v-container>
          <v-divider></v-divider>
          <v-col cols="12">
            <v-btn color="primary" outlined @click="addRule"> Add </v-btn>
          </v-col>
          <div v-for="(rule, index) in rules" :key="rule.id">
            <mainbox :rule-prop="rule" :idx="index" @remove="removeRule" />
          </div>
          <v-divider></v-divider>
          <v-alert outlined type="success" text>
            <b>this.rules :</b>  {{ rules }}
          </v-alert>
          <v-alert v-show="empty" outlined type="warning" text>
            <b>fill all the fields</b>
          </v-alert>
        </v-container>
      </v-list-item-content>
    </v-list-item>
  </v-card>
</template>

<v-app id="app">
  <parent title="$CODE_08" />
</v-app>

  •  Tags:  
  • Related