Functional requirements

After clicking the button, the popup box displays the personnel that can be checked. Level-1 node is the class, and level-2 node is the personnel in the class. At the same time, the system provides conditional search, and the qualified candidates are displayed after the search. All the checking operations are carried out in a pop-up page. After the user has searched and selected all personnel for several times, click “OK” and click “Submit” to send the data to the back end.

The first analysis (logic of failure)

The first thing you might want to do is use the el-Tree’s own check-change or Node-click event to retrieve the check array after each operation. However, the problem is that we can only retrieve the data of the node that meets the current condition. If the user has checked the person other than the condition before, We won’t get it.

At this point, I thought, let’s store the data of each conditional search temporarily. As soon as the search status changes, we will insert all the people checked in this conditional search into the cache. And new problems come, if the last time I checked that the king of the students, in the cache, the name is wang search all the conditions of my classmates, I found my hook wrong ah, so I cancelled the students one by one check to the king, but because I every time is the last to insert a new member of the new check, do not have to uncheck the delete operation for personnel. Therefore, we need to add an operation to judge that when the check state changes each time, compare the length of the returned array with that of the last cache array. If the length is lower than that of the last cache, the thief will remove the person from the cache each time he unchecks the check box.

In fact, I think the general idea is already there, so I used it the first time I implemented this feature. But when I looked at my own code after I had written it, it felt very messy, illogical, unclear, and prone to all kinds of hard to maintain bugs. So in the second implementation of a similar function, I chose a different idea, abandoned the overall return of check-change, and decided to start from the [check] operation itself to cache.

The logic of the second time (can be directly read here)

If we start with the check operation itself, we don’t need to worry about the total check array returned by check-change, we just need to consider whether we check or uncheck this operation, check will add the person to the cache, uncheck will delete the person from the cache.

This idea is simple, clear and easy to maintain.

And then since I’m going to pass the authorized person ID array to the back end is going to be the object with the corresponding class ID as the key value, I’m going to pass a total array object. Such as:

[{'43574521': [001.002. ] },// The key value is the class ID
      {'56744522': [034.056. ] },// value Indicates the ID of the class to be authorized. ]Copy the code

So after checking whether the operation is checked or unchecked, I also check whether it is a class:

  1. If class is checked, whether the class exists in the cache. If not, the whole class will be inserted into the cache. If yes, the cache of some members of the original class will be directly replaced by the cache of the whole class.
  2. Uncheck the class, I want to delete the entire class cache;

If not the class, but the individual operation of personnel:

  1. Personnel check: whether there is a cache in the class of the personnel, if so, the personnel will be inserted into the class cache, if not, first create the class object in the cache, and then the personnel will be inserted into the class object;
  2. Personnel uncheck: the corresponding class object is circularily retrieved, and the personnel object in the class object is deleted;

At this point, my basic operation logic came out. I feel that it basically covers all possibilities, and the logic is clear and orderly, simple and easy to understand, and easy to maintain.

Although at first I gave up the overall return of check-change, which seemed to be giving up the quick and easy method, in the end I found that it was much more convenient and concise to cache data using the state response of a separate operation.

code

1. HTML code and some attribute explanation

El – tree code:

        <el-tree :props="studentsProps"
                 :data="studentsList"
                 node-key="id"
                 ref="studentsTree"
                 :default-expanded-keys="defaultKeys"
                 :default-expand-all="false"
                 show-checkbox
                 @check-change="studentsCheckChange"
                 empty-text="No user to authorize">
        </el-tree>
Copy the code

Data:

    data () {
      return {
      ruleForm: {
        hasCheckedClass: [].// Class collection is checked
      },
      // Assign a popover to select a student
      studentSearch: {
        className: ' '.studentName: ' '
      },
      // Student number prop
      studentsProps: {
        children: 'students'.label: 'userName',},studentsList: []./ / student list
      lastCheckedClass: [].// Render for closing the popover and then opening it for personnel modification operation
    },
Copy the code

2. Code for a single check operation

      // Select when the node changes
      studentsCheckChange (data, node) {
        // data is the data of the selected node object
        // Nodestatus is a Boolean object
        // True indicates that the operation is checked. False indicates that the operation is unchecked
        if (data.isClass) {
        // Check if it is a class
        // isClass is set by myself after recursive processing when I get the student array, recursively traversing whether there is classId in the data layer, if there is, set to true, if not, set to false
        // Although, it would be nice if the back end could handle it for me
          if (node) {
            // If yes, put all student uids in it
            let _uuidList = data.students.map((item) = > {
              return item.id
            })
            this.ruleForm.hasCheckedClass.push({
              [data.classId]: _uuidList
            })
          } else {
            // Delete the class IDs object if it is cancelled
            // Get the selected position of the class and delete it
            let _index
            this.ruleForm.hasCheckedClass.forEach((item, index) = > {
            Keys (item)[0] if you can't read object.keys (item)[0], see the array example above
            // Then print it out for yourself
              if (Object.keys(item)[0] == data.classId) {
                _index = index
              }
            })
            this.ruleForm.hasCheckedClass.splice(_index, 1)}}else {
          // If it is not a class, check or cancel first
          if (node) {
            // If non-class nodes are selected, check whether the selected classes already have class ids
            let _isChecked
            let _index
            this.ruleForm.hasCheckedClass.forEach((item, index) = > {
              if (Object.keys(item)[0] == data.classId) {
                _isChecked = true
                _index = index
              } else {
                _isChecked = false}})if (_isChecked) {
              // If yes, add it according to the class ID
              this.ruleForm.hasCheckedClass[_index][data.classId].push(data.id)
            } else {
              // If it does not exist, add the class object
              this.ruleForm.hasCheckedClass.push({
                [data.classId]: [data.id]
              })
            }
          } else {
            // If the non-class node is cancelled
            // Get the node's position in the selected class and delete it
            let _index
            let _classId = data.classId
            this.ruleForm.hasCheckedClass.forEach((item, index) = > {
              if (Object.keys(item)[0] == data.classId) {
                _index = index
              }
            })
            if (_index || _index == 0) {
              let _userIDList = this.ruleForm.hasCheckedClass[_index][_classId]
              let _userIndex
              _userIDList.forEach((item, index) = > {
                if (item === data.id) {
                  _userIndex = index
                }
              })
              _userIDList.splice(_userIndex, 1)
              this.ruleForm.hasCheckedClass[_index][_classId] = _userIDList
            }
          }
        }
      },
Copy the code

The second time the new idea is basically like this, I personally feel that it is easier to understand. This logic is much more convenient and concise than my first one, I now look back at my first code, it is a bit confusing…

Do an archive and share.