【问题标题】:Aurelia repeat.for throws an undefined error with custom-elementAurelia repeat.for 使用自定义元素引发未定义错误
【发布时间】:2018-02-21 12:50:45
【问题描述】:

我想传递一个对象数组。

我使用repeat.for 语法将商店数组从一个自定义元素“Store”传递到另一个自定义元素“store-front”。

我最初调用了 store-frontstore 并将其更改为 store-front,以防万一 - 但它没有。

我可以将数组记录在“存储”自定义元素中。我还记录了它的实例(它是一个数组)。

以下是错误:

aurelia-task-queue.js?26b6:44 Uncaught TypeError: Cannot set property 'undefined' of undefined
at setKeyed (aurelia-binding.js?1bbb:1923)
at AccessKeyed.assign (aurelia-binding.js?1bbb:1461)
at NameBinder.bind (aurelia-binding.js?1bbb:5174)
at View.bind (aurelia-templating.js?f83c:1396)
at Controller.bind (aurelia-templating.js?f83c:3394)
at View.bind (aurelia-templating.js?f83c:1406)
at Repeat.addView (repeat.js?1ef5:240)
at ArrayRepeatStrategy._standardProcessInstanceChanged (array-repeat-strategy.js?783a:107)
at ArrayRepeatStrategy.instanceChanged (array-repeat-strategy.js?783a:29)
at Repeat.itemsChanged (repeat.js?1ef5:136)
at BehaviorPropertyObserver.selfSubscriber (aurelia-templating.js?f83c:3645)
at BehaviorPropertyObserver.call (aurelia-templating.js?f83c:3512)
at BehaviorPropertyObserver.setValue (aurelia-templating.js?f83c:3492)
at Repeat.descriptor.set [as items] (aurelia-templating.js?f83c:3600)
at Object.setValue (aurelia-binding.js?1bbb:3539)
at Binding.updateTarget (aurelia-binding.js?1bbb:4778)
at Binding.call (aurelia-binding.js?1bbb:4793)
at SetterObserver.callSubscribers (aurelia-binding.js?1bbb:295)
at SetterObserver.call (aurelia-binding.js?1bbb:3612)
at TaskQueue.flushMicroTaskQueue (aurelia-task-queue.js?26b6:140)
at MutationObserver.eval (aurelia-task-queue.js?26b6:68)

我在某处读到,当 Aurelia 附加数组观察者时,它就变成了一个对象。但我找不到任何有关如何处理此问题的文档。

我可以将商店传递给商店 html 中的普通 div - 但我更喜欢更加模块化/可组合。

Stores.js

import { customElement, useView, inject, bindable } from 'aurelia-framework'
import { EventAggregator } from 'aurelia-event-aggregator'
import { DialogService } from 'aurelia-dialog'
import { HttpClient } from 'aurelia-http-client'
import { getStoresTask, toVm } from './model'
import { getStoreTask } from './store-front/model'
import { style } from './style.css'
import { map, clone } from 'ramda'

@customElement('stores')
@useView('./stores.html')
@inject(EventAggregator, HttpClient, DialogService)
export class Stores {
  @bindable tenants
  @bindable userId
  constructor( emitter, http, modal ) {
    this.disposables = new Set()
    this.data = {}
    this.state = {}
    this.emitter = emitter
    this.http = http
    this.errors=[]
    this.style=style
  }

  attached() {
    this.reset()
    this.getStores()
  }

  getStores() {
    const onError = error =>
      console.error(error);

    const onSuccess = data => {
      this.data.stores = data
      console.log(this.data.stores)
      this.emitter.publish('loading-channel', false)
    }

    this.emitter.publish('loading-channel', true)
    getStoresTask(this.http)(this.userId).fork(onError, onSuccess)
  }

  // openModal(id) {
  //   this.this.modal.open( {viewModel: Store, model: id })
  // }

  reset() {
  }


}

Stores.html

<template>
  <require from="material-design-lite/material.css"></require>
  <require from="./store-front/store-front"></require>

  <div class="store-collection">
    <div class=" mdl-grid">
      <store-front repeat.for="store of data.stores" store-front.bind="store"></store-front>
    </div>
  </div>
</template>

store-front.js

import { customElement, useView, inject, bindable } from 'aurelia-framework'
import { DialogController } from 'aurelia-dialog'
import { HttpClient } from 'aurelia-http-client'
import { getStoreTask } from './model.js'
import { style } from './style.css'

@customElement('store-front')
@useView('./store-front.html')
@inject(HttpClient, DialogController)
export class StoreFront {
  @bindable storeFront
  constructor( http, dController ) {
    this.disposables = new Set()
    this.dController = dController
    this.store = ''
    this.id = null
    this.state = {}
    this.http = http
    this.style = style
  }

  attached() {
    this.reset()
    this.getStore()
  }

  getStore(id) {
    const onError = error => {
      console.error(error);
      this.errors.push({type:'store', msg: 'error with getting store'})
    }

    const onSuccess = store => {
      this.store = store
      this.errors['store'] = ''
      this.openModal(id)
      this.emitter.publish('loading-channel', false)
    }

    this.emitter.publish('loading-channel', true)
    getStoreTask(this.http)(id).fork(onError, onSuccess)
  }


   colorChange() {
    //  console.log(typeof this.storeColors);
      // TODO: grab  b/ style and create a fucntion that chnages the color based on another input
      changeStoreColors(this.storeColors)
   }

   reset() {
     console.log('store?',this.store)
   }

}

store-front.html

<template>
  <div class="mdl-cell mdl-shadow--2dp mdl-grid__item mdl-grid__item--three-div" css="${style.storeColor}" ref="storeColors[$index]"}>
    <span class="mdl-grid__item-primary-content">
        <svg style="width:24px;height:24px" viewBox="0 0 24 24">
          <path fill="#000000" d="M9,19V13H11L13,13H15V19H18V10.91L12,4.91L6,10.91V19H9M12,2.09L21.91,12H20V21H13V15H11V21H4V12H2.09L12,2.09Z" />
        </svg>
      <span>${store.name}</span>
      <span class="mdl-grid__item-text-body">
        <p>Expiration Date: ${store.expirationDate} <br>
          Notification Date: ${store.notificationDate}</p>
      </span>
    </span>
    <span class="mdl-grid__item-secondary-content">
      <a class="mdl-grid__item-secondary-action" href="#"><i class="material-icons">star</i></a>
      <button class="mdl-button mdl-button--compact mdl-button--theme-dark mdl-card__action mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" click.delegate="showStore(store._id)">MORE DETAIL</button>
    </span>
  </li>
  </div>
<template >

【问题讨论】:

  • 您介意将代码作为文本发布吗?这将使复制问题变得更加容易。
  • 当然——我会用代码编辑问题
  • 从您的堆栈跟踪来看,这显然是与通过.ref 进行的引用绑定相关的错误/错误,您可以删除所有相关的引用绑定并重新检查结果吗?或者至少尽量避免使用具有相同值的ref

标签: binding aurelia


【解决方案1】:

更新:

堆栈追溯到.ref 绑定。首先检查所有ref 绑定。这里还有一个与ref和继承相关的问题,你可以看看以防遇到同样的问题https://github.com/aurelia/templating/issues/533


原文:

看起来这条线是你store.html中的问题

<store-front repeat.for="store of data.stores" store-front.bind="data.stores"></store-front>

注意store-front.bind=data.stores,您绑定的是数组而不是data.stores 中的每个商店。

【讨论】:

  • 很抱歉,这是复制时的拼写错误。我在玩不同的单词组合(this.data.stores vs this.stores 等)。我会在我的问题中改变它。谢谢你指出这一点
【解决方案2】:

我很确定问题是由两件事引起的:

  1. 您正在尝试访问视图中datastores 属性,即使该属性在数据绑定时不存在。

  2. 您正在使用attached 回调调用getStores

我首先为data 对象中的stores 属性创建一个空数组:

this.data = { stores: [] }

我会改用bind 回调而不是attached

最后,您可能需要添加一个if.bind="data.stores.length &gt; 0" to thestore-front` 元素:

 <store-front if.bind="data.stores.length > 0" 
              repeat.for="store of data.stores" 
              store-front.bind="store"></store-front>

在这种情况下,将if.bind 放在repeat.for 之前很重要,以便优先。

如果这有帮助,请告诉我!

【讨论】:

  • 嗨 Ashley - 谢谢你的回复,我切换到了 bind 方法,在 Stores 的 data 属性中添加了一个空的 stores 数组,并将你的代码复制/粘贴到 Store.html - 我还有同样的错误。我还尝试将 if 语句调整为仅查找 data.stores if.bind="data.stores" 并从 data 属性中删除 stores 属性仍然没有骰子
  • 好的,那么我们需要继续创建一个 gist.run 可运行的 repro。我要去睡觉了,但如果你能在 gist.run 上运行 repro,我会在早上看。
  • 我仍在寻找最新的 aurelia gist / plunker 用作骨架来复制此问题....
  • 我很确定这是因为 Aurelia 附加了将数组转换为对象的 SetterObserver。
猜你喜欢
  • 2016-07-02
  • 2018-09-18
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
  • 1970-01-01
  • 2015-03-28
  • 2018-03-27
  • 1970-01-01
相关资源
最近更新 更多