VueJS + Axios本地JSON嵌套过滤

时间:2019-08-27 14:49:24

标签: json vue.js search filter axios

希望推断Vue中已存在的JSON搜索/过滤/匹配功能,该功能可用于计算函数。这是我的情况。

我有一个本地JSON文件(简称为 ):

更新了JSON以反映最新进展

{
  "examplejson": [
    {
      "section_title": "title 1",
      "section_category": "category1",
      "items": [
        {
          "category": "category1",
          "title": "item title 1",
          "url": "url 1",
          "description": "Etiam turpis ipsum, gravida a odio ac, sollicitudin egestas tortor.",
          "footnote": "footnote 1" 
        },
        {
          "category": "category1",
          "title": "item title 2",
          "url": "url 2",
          "description": "Suspendisse consectetur lacus sed maximus consectetur. Etiam nunc magna, fringilla.",
          "footnote": "footnote 2"
        }
      ]     
    },
    {
      "section_title": "title 2",
      "section_category": "category2",
      "items": [
        {
          "category": "category2",
          "title": "title 3",
          "url": "url 3",
          "description": "Donec venenatis justo at ligula dictum tempus. In euismod nulla.",
          "footnote": "footnote 3"
        },
        {
          "category": "category2",
          "title": "title 4",
          "url": "url 4",
          "description": "Cras dui felis, pulvinar vel elit quis, imperdiet sollicitudin massa.",
          "footnote": "footnote 4"
        }
      ]
    }
  ]
}

这里是我的Vue组件:

import Vue from 'vue';
import axios from 'axios';

Vue.component('searchableList', {
  template: `   
    <!-- Searchable List Component -->
    <div v-cloak>
       <label class="search-bar">
         <input type="text" class="search__input" v-model="searchString" placeholder="Search...">
       </label>

       <div class="searchable-content">
         <ul class="list">
           <li :class="section.section_category + '-section'" v-for="section in filteredList" :key="section.section_title">
             <h3 class="section-title">{{ section.section_title }}</h3>
             <ul :class="section.section_category + '-section-list'">
               <li v-for="item in section.items">
                 <a :href="item.url">{{ item.title }}</a>
                 <p>{{ item.description }}</p>
                 <p class="note">{{ item.footnote }}</p>
               </li>
             </ul>
           </li>
         </ul>
       </div>
     </div>
     `
      //other items listed below are contained within this component but I separated into individual segments for clear explanation
   });

组件数据('componentLoaded'标志可消除计算属性与axios.get方法之间的竞争条件):

data() {
  return {
    componentLoaded: false,
    list: [],
    searchString: ''
  }
},

// mounted lifecycle hook:
mounted() {
  this.getListData();
}

// Axios JSON localized JSON get method:
methods: {
  getListData() {
    var self = this;
    const url = '/path/to/localized/list.json';
    axios.get(url)
      .then(response => {
        self.list = response.data.examplejson;
      })
      .then(function() {
        self.componentLoaded = true;
        console.log("content loaded");
      })
      .catch(error => {
        console.log("The file:" + ` "${url}" ` + "does not exist or path/filename is incorrect.");
      });
  }
},

// Computed filtered list property (this is where im having trouble):
computed: {
  filteredList: function() {
    let self = this;

    if (!self.componentLoaded) {
      return null;
    } 
    else {
      console.log("list loaded successfully");
      return self.list;
    }
  }
}

DOM中的组件注入点(有条件确定页面中是否存在类,需要单独的页面DOM控制,选择没有全局注入点):

if (document.getElementsByClassName("my-list")[0]){
  new Vue({
    el: ".my-list"
  });
}

HTML:

<div class="container">
  <div class="my-list">
    <searchable-list></searchable-list>
  </div>
</div>

我的一般问题是我的过滤器函数(filteredList)和内容呈现(getListData())变得过于复杂,因此我的搜索过滤不起作用,或者我只是没有正确构建我的搜索过滤器,因为我不完全了解我的JSON数组。这就是我需要的帮助。

预期行为的简单说明:

为列表创建空数组。创建用于搜索查询的空字符串。为axios请求和计算的属性注入之间的竞争条件创建标志,并将其设置为false。

Component通过向JSON(axios.get())发出请求,并将该axios.get()请求的响应分配给本地JSON数据,从而基于本地JSON文件数据呈现嵌套对象(“项目”)列表。我的数据()中的空列表数组。然后,在完成axios请求并将其分配给空数组之后,将标志设置为true。

然后,基于标志是否为true或false,将具有返回的新形成的JSON数据的列表数组通过filteredList的计算属性并将其分配到最高级别的v-for循环中注入到vue组件中(以及随后的嵌套v-for循环(用于其余嵌套内容)。

帮助区域

我要挂断电话的地方是我需要根据查询字符串('searchString')过滤(.filter()函数)内容的搜索输入,然后(我认为我需要方法是:根据匹配(.match()函数)将JSON对象重新呈现给查询字符串。我只需要过滤每个部分中的“项目”数组(并可能返回适用的section_title)。

似乎计算属性上的基本过滤器功能以及将所有匹配项返回到searchString数据查询均无法正常工作。我一直在尝试如下操作:

computed: {
  filteredList: function() {
    let self = this;

    if (!self.componentLoaded) {
      return null;
    } 
    else {
      let listData = self.list;

      //-- new search code --//
      let searchItem = listData.section.items;

      return calcData.filter((searchItem) => {
        return searchItem.title.toLowerCase().match(this.searchString.toLowerCase());
      });

      //-----//
    }
  }
}

或更坚固的东西:

computed: {
  filteredList: function() {

    let self = this;
    if (!self.componentLoaded) {
      return null;
    } 
    else {
      let listData = self.list;

      //-- new search code --//
      let searchItem = listData.section.items;
      let searchTerm = (this.searchString || "").toLowerCase();

      return listData.filter(function(searchItem) {
        let title = (searchItem.title || "").toLowerCase();
        let description = (searchItem.description || "").toLowerCase();
        let footnote = (searchItem.footnote || "").toLowerCase();

        return title.indexOf(searchTerm) > -1 || description.indexOf(searchTerm) > -1 || footnote.indexOf(searchTerm) > -1;
      });

      //-----//
    }
  }
}

这两个函数在控制台中都返回相同的错误:

TypeError: Cannot read property 'items' of undefined

我可以使用以下命令console.log每个键中的任何/所有项目:

console.log(JSON.stringify(self.list.KEY_1.items));

哪个很棒,但无关紧要。但实际上,这只是确认我的嵌套设置正确(?)。

我在想也许我没有正确地遍历所有初始对象(带有键)的事实。或/也由于我有一个通用的JSON对象(“ examplejson”),其中包含多个子对象(2个具有自定义键的同级对象(“ KEY_1”,“ KEY_2”)),还有其他嵌套对象(“ section_title”), “ section_category”)和另一个嵌套的兄弟对象(“ items”),其中包含对象数组,这可能导致我的“简单”调用实际上需要更复杂的标识/操作顺序,因此需要更多复杂/健壮的过滤机制?

或者还是因为比赛条件? (我对此表示怀疑,因为控制台日志显示首先发出axios.get()请求,然后在将标志设置为true时运行条件运算的函数)。

或者也许是完全不同的东西,我什至没有注意到。

对于方向或我在做对/错的任何帮助或澄清,我们将不胜感激。我对Vue还是很陌生,但仍然想弄清楚。预先感谢。

***** UPDATE *****

我现在可以通过删除键(“ KEY_1”,“ KEY_2”)并将“ examplejson”对象转换为数组来成功过滤基于“ section_title”的结果(示例中已进行了更新) )。我可以定位section_title并返回包含“ section_title”的整个对象,其中还包含“ items”数组。

*****更新了仅适用于“ section_title”定位**的计算功能**

computed: {

  filteredList: function(){

       let self = this;

       if(! self.componentLoaded) {

            return null;

       } else {

            let listData = self.list;

            //-- new working search code for section objects ONLY --//

            let searchItem = listData.section;

            return listData.filter((searchItem) => {
                     return searchItem.section_title.match(this.searchString);
            });

            //-----//

       }

  }

 }

现在的问题是,除了定位“ section_title”字符串外,我还需要更深入一层并定位items数组中的内容。只是将.items附加到searchItem变量中,使其读取let searchItem = listData.section.item;let searchItem = listData.section.items;不起作用并返回Cannot read property 'item' of undefined,所以我不确定如何除了items以外,还应正确定位section_title数组中的对象。

任何帮助表示赞赏

1 个答案:

答案 0 :(得分:0)

const list = [
  {
    "section_title": "title 1",
    "section_category": "category1",     
    "items": [
      {
        "category": "category1",
        "title": "item title 1",
        "url": "url 1",
        "description": "Etiam turpis ipsum, gravida a odio ac, sollicitudin egestas tortor.",
        "footnote": "footnote 1" 
      },
      {
        "category": "category1",
        "title": "item title 2",
        "url": "url 2",
        "description": "Suspendisse consectetur lacus sed maximus consectetur. Etiam nunc magna, fringilla.",
        "footnote": "footnote 2"
      }
    ]     
  },
  {
    "section_title": "title 2",
    "section_category": "category2",
    "items": [
      {
        "category": "category2",
        "title": "title 3",
        "url": "url 3",
        "description": "Donec venenatis justo at ligula dictum tempus. In euismod nulla.",
        "footnote": "footnote 3"
      },
      {
        "category": "category2",
        "title": "title 4",
        "url": "url 4",
        "description": "Cras dui felis, pulvinar vel elit quis, imperdiet sollicitudin massa.",
        "footnote": "footnote 4"
      }
    ]
  }
]; 

const searchString = 'item';        
const filteredList = list.filter((section) => {
  // `section` here is an arbitrary variable name to represent the individual element in the `listData`
  console.log('section', section);

  // If section_title contains searchString, add the element to the filtered result
  if (section.section_title.indexOf(searchString) > -1) {
    return true;
  }

  // section_title does not contain searchString,
  // proceed to check for each section.items if they contain searchString
  const hasItemContainsSearchString = section.items.some((item) => {
    // `item` here represents the individual element of section.items
    console.log('item', item);

    // Check if the title contains searchString
    return item.title.indexOf(searchString) > -1;
  });

  return hasItemContainsSearchString;
});

console.log('filteredList', filteredList);