简体   繁体   中英

Checking a substring from a programmatically added element in VueJs

I have a form that adds a new line on a button click. The new line must check for logic independently. In this case, it's chacking the first 2 digits of a barcode and associating it to a data set to see if it matches and return the appropriate value or "nothing found". I can't seem to get this right. First, it's not really evaluating at all. It only gives me "No Agency found" and second, it's doing it for all fields (because they all have the same v-model on a new line add). How can I achieve this so that it evaluates correctly and independently from each other?

Here's the relevant code in my template and script

<div id="q-app" class="q-pa-lg">
 <div class="col-6">
  <div v-for="(barcodefield, index) in barcodefields" :key="index">
   <div class="flex q-pt-lg">
    <div class="row flex-center">
     <div class="col-3">
      <div class="column">
       <div class="row q-pr-lg items-center">
        <label class="text-weight-medium">Starting Roll #:</label>
        <q-input outlined square dense maxlength="24"
         v-model.trim="barcodefield.start" ref="bcentry"></q-input>
       </div>
      </div>
     </div>
     <div class="col-3">
      <div class="column">
       <div class="row q-pr-lg items-center">
        <label class="text-weight-medium">Ending Roll #:</label>
        <q-input outlined square dense maxlength="24"
         v-model.trim="barcodefield.end" @blur="showAgencyName" ref="bcentry"></q-input>
       </div>
      </div>
     </div>
     <div class="col-5">
      <div class="column">
       <label class="text-weight-medium">
        Agency:
       </label>
       <div v-if="agencyName" style="min-height: 40px">
        {{ agencyName }}
       </div>
       <div v-else style="min-height: 40px"></div>
      </div>
     </div>
     <div class="col-1">
      <div class="block float-right">
       <q-btn v-if="index + 1 === barcodefields.length" @click="addLine" icon="add" color="primary" round />
       <q-btn v-else style="min-width: 42px"/>
      </div>
     </div>
    </div>
   </div>
  </div>
 </div>
</div>


export default {
  data() {
    return {
        barcodefields: [],
        barcodeprefixes: {
            "10": "Boston",
            "11": "New York",
            "13": "Houston",
            "14": "Connecticut",
            "16": "SIA",
            "17": "Colorado",
            "18": "Chicago",
            "19": "Washington",
        },
        barcodefield: {
          star: "",
          end: ""
        },
        agencyName: "",
    };
  },
  methods: {
    addLine() {
        this.barcodefields.push({
            start: null,
            end: null
        });
    },
    showAgencyName() {
        var str = this.barcodefield.end;
        var res = str.substring(0, 2);
        if (this.barcodeprefixes[res] == undefined) {
            this.agencyName = "Agency not found";
        } else {
            this.agencyName = this.barcodeprefixes[res];
        }
    },
  },
  mounted() {
    this.addLine();
  } 
}

Here is a codepen for you.

There are a couple of problem with this. First, you have a typo in the barcodefield data object. You have "star" instead of "start".

Secondly in the showAgency method you are referencing the this.barcodefield properties but that doesn't exist. What you can do is pass the index of the barcodefield to the showAgencyName method, and use that inside the method to get the desired barcodefield from the barcodefields array.

In your html:

<q-input outlined square dense maxlength="24"
v-model.trim="barcodefield.end" @blur="showAgencyName(index)" ref="bcentry"></q-input>

and the showAgencyName method:

showAgencyName(index) {
    const barcodefield = this.barcodefields[index]
    var str = barcodefield.end;
    var res = str.substring(0, 2);

    if (this.barcodeprefixes[res] == undefined) {
        this.agencyName = "Agency not found";
    } else {
        this.agencyName = this.barcodeprefixes[res];
    }
}

UPDATE: There is another problem that I didn't notice at first. The agencyName is overwritten every time you add a new barcodefield since it is kind of a global value. I update the Codepen with the simplest solution I could think of. Return the name of the agency from the showAgencyName and use that to print it on the interface. There are many possible other solutions to this (for example add the name the the barcodefields object in the array).

Here is a working Codepen

  • First you should change name of the for loop variable named "barcodefield", beacause you already have one in your data structure
  • Second, i would personnaly use a function {{ getAgencyName(b) }} instead of {{ agencyName }} otherwise you will have same agency name for all lines

There are several things going on here:

First, as Simon points out, don't name loop variables the same thing as a top-level data element. Instead of <div v-for="(barcodefield, index) in barcodefields" :key="index"> , do <div v-for="(item, index) in barcodefields" :key="index"> . Then update all the barcodefield.start and barcodfield.end references to item.start and item.end .

Then, you need to get each item to have its own agencyName , instead of all of them referring to the same data.

Update showAgencyName to this:

showAgencyName(item) {
    var str = item.end;
    var res = str.substring(0, 2);
    if (this.barcodeprefixes[res] == undefined) {
        item.agencyName = "Agency not found";
    } else {
        item.agencyName = this.barcodeprefixes[res];
    }
},

Then you can call it like this: @blur="showAgencyName(item)"

And use it in the html like so:

<div v-if="item.agencyName" style="min-height: 40px">
    {{ item.agencyName }}
</div>

(And you can get rid of the top-level barcodefield in the data object, because it's not used anymore.)

Fiddle here: https://jsfiddle.net/ebbishop/7r1pqx9f/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM