错误时更新 Vue 中的计算属性(表单)?

Posted

技术标签:

【中文标题】错误时更新 Vue 中的计算属性(表单)?【英文标题】:Updating a computed property (Form) in Vue on error? 【发布时间】:2018-11-22 03:03:27 【问题描述】:

好的,所以我跟着整个 Vue Laracasts 视频,最终有一个 Form 和一个 Errors 类。这是视频中 repo 的 github 链接:

https://github.com/laracasts/Vue-Forms/blob/master/public/js/app.js

现在我要做的是集成 Vuex 以跟踪我当前登录的用户,用当前值预填充表单,并在任何 Laravel 验证失败时显示错误。

我似乎遇到的问题是我必须将我的 authUser 设置为计算属性,才能从 Vuex 商店中提取它。然后,由于我不能在数据中设置的任何内容中使用这些,我不得不将我的表单移动到计算属性。现在它是一个计算属性,它永远不会更新,所以即使抛出错误,我的表单也永远不会出错。

这是我的路由文件Account.vue

<template>
<div>
    <form @submit.prevent="onSubmit" @keydown="form.errors.clear($event.target.name)">
        <div class="row">
            <div class="form-group col-md-6 col-lg-3">
                <label>Name</label>
                <input type="text" class="form-control" name="user" autocomplete="false" v-model="form.name">
                <span class="help is-danger" v-if="form.errors.has('name')" v-text="form.errors.get('name')"></span>
            </div>
            <div class="form-group col-md-6 col-lg-3">
                <label>Email address</label>
                <input type="email" class="form-control" placeholder="Enter email" autocomplete="false" name="email" v-model="form.email">
                <span class="help is-danger" v-if="form.errors.has('email')" v-text="form.errors.get('email')"></span>
            </div>
            <div class="form-group col-lg-3">
                <label>Password</label>
                <input type="password" class="form-control" placeholder="Password" autocomplete="false" name="password" v-model="form.password">
                <span class="help is-danger" v-if="form.errors.has('password')" v-text="form.errors.get('password')"></span>
            </div>
        </div>

        <div class="col-12">
            <button type="submit" class="btn btn-primary">Submit</button>
        </div>
    </form>
</div>
</template>

<script>
export default 
    computed: 
        authUserName: 
            get: function() 
                return this.$store.getters.getAuthUser.name;
            ,
            set: function(value) 
                this.$store.commit('setAuthUserValue',  key: 'name', value )
            
        ,
        authUserEmail: 
            get: function() 
                return this.$store.getters.getAuthUser.email;
            ,
            set: function(value) 
                this.$store.commit('setAuthUserValue',  key: 'email', value )
            
        ,
        form() 
            return new Form(
                name: this.authUserName,
                email: this.authUserEmail,
                password: ''
            )
        
    ,

    data() 
        return 

        
    ,

    mounted() 
    ,

    methods: 
        onSubmit() 
            this.form
                .patch('/current-user')
                .then(status => 
                    this.$emit('success', status);
                );
        
    

</script>

index.js

import AuthUser from "../models/AuthUser";

export default new Vuex.Store(
state:  // = data
    authUser: 
        name: null,
        email: null,
    
,

getters:  // = computed properties
    getAuthUser(state, getters) 
        return state.authUser;
    
,

actions:  // = methods
    fetchAuthUser(context) 
        AuthUser.load(user => 
            context.commit('setAuthUser', user);
        );
    
,

mutations: 
    setAuthUser(state, user) 
        Vue.set(state, 'authUser', user);
    ,
    setAuthUserValue(state, payload) 
        state.authUser =  ...state.authUser, payload 
    

);

app.js

import router from './routes';
import Hamburger from './components/Hamburger';
import NavHeader from './components/NavHeader';
import store from "./store/index";

new Vue(

el: '#app',
components: 
    Hamburger,
    NavHeader
,

data() 
    return 

    
,

created() 
    store.dispatch('fetchAuthUser');
,
router,
store
);

我曾尝试与观察者混在一起,但一切都会出错。我非常努力地使用预设的现有用户值创建表单,并建议尝试使用 vuex,但现在遇到了这些问题,现在需要计算表单而不是在数据中设置,所以表单永远不会现在有错误。抱歉,我一下子就学会了所有这些新东西哈哈。

编辑

我现在还尝试将表单设置为数据中的空表单对象,然后在mounted() 中设置属性,但无论我如何尝试在mounted 中访问authUser,我都无法定义。

mounted() 
    console.log(this.authUser);
    console.log(this.authUser.name);
    console.log(this.$store.getters.getUser.name);
,

输出...

ob:观察者

未定义

未定义

编辑 2

更新了最新代码,但仍然没有在输入下方显示错误,尽管它们确实显示在开发工具中。 根>帐户>计算>表单>错误>错误

如果我将它们留空,它会在其中列出名称和电子邮件错误。可能是因为它是双重嵌套的吗?我知道这是一个关于如何嵌套 json 响应的 Laravel 问题。

可能是 app.js 中的 Form 或 Errors 类中的某些内容?

【问题讨论】:

不应该 authUser: []authUser: 吗? 如果是这样,您应该在setUser 中设置其状态,使用:Vue.set(state, 'authUser', user); 改变了这两行,仍然是同样的问题。无法更新表单,因为它现在是计算属性,因为我无法将表单默认名称和电子邮件设置为存储的 authUser 名称和电子邮件而不将其设置为计算? 看看vue lifecycle diagram。而不是使用computed 属性来设置表单值,您应该使用data,并在createdmounted 方法(或任何其他可用方法)中从存储中分配初始值 @ljubadr hm 我试过了,通过在数据中创建一个空的表单对象,然后设置它的值。知道为什么 this.authUser.name 在挂载或创建时会未定义吗? 【参考方案1】:

AuthUser.load 是一个asynchronous 函数,当您在created 挂钩中执行它时,不能保证authUsers 值将在Account.vuecreated 设置时设置钩子被触发。

现在您遇到的问题是由于您有一个没有setter 的计算属性。 Form 类尝试 mutate the value of the store directly,这将导致控制台爆炸。

如果您为您的值提供setter,当您尝试写入它时,您可以对传递给setter 的值做出反应,您可以将该值发送(或在您的情况下,提交)到商店:

computed: 
   authUser: 
      get(): 
          return this.$store.getters.getUser;
      ,
      set(value): 
          this.$store.commit('setUser', value)
      
   

但是等等,这仍然行不通!为什么?因为您将收到的值只是文本输入值,您如何知道要更新AuthUser 中的哪个属性?可能最简单的解决方法是创建一个computed property for each property on the authUser

computed: 
   authUserName: 
      get(): 
          return store.getters.getUser.name;
      ,
      set(value): 
          this.$store.commit('setUser',  key: 'name', value )
      
   ,
   authUserEmail: 
      get(): 
          return store.getters.getUser.email;
      ,
      set(value): 
          this.$store.commit('setUser',  key: 'email', value )
      
   ,
   authUserPassword: 
      get(): 
          return store.getters.getUser.password;
      ,
      set(value): 
          this.$store.commit('setUser',  key: 'password', value )
      
   

现在您可以使用每个 getter 实例化表单:

new Form(
    name: this.authUserName,
    email: this.authUserEmail,
    password: this.authUserPassword
)

但是,再一次,这仍然行不通!我们需要一个新的突变,它只会写入我们的authUser 的属性

setUserValue(state, payload) 
   state.authUser =  ...state.authUser, payload 

通过使用简单的解构,我们可以覆盖 authUser 的属性并合并计算属性的新值。

现在您需要更新您的computed properties 并在您的设置器中使用this.$store.commit('setUserValue', key: 'name/email/password': value)

最后,您的authUser 应该是具有预设属性的对象:

authUser: 
    name: null,
    email: null,
    password: null

这很重要,因为properties of an object are reactive。但是,如果将属性添加到对象,you cannot simply overwrite the object and have new reactive properties。为此,您需要使用Vue.set(),例如:

setUser(state, user) 
    Vue.set(state, 'authUser', user)

这将正确地允许观察到的属性变为反应性。这是 VueX 商店响应性中的一个重要概念。这也是你的价值观是undefined的原因。

【讨论】:

请记住,我不相信他将商店添加到app.js 中的基本 vue 组件中 @Derek 我现在,我已经更新了原始代码 sn-ps。 @Octoxan 我还是没看到 @Ohgodwhy 现在用最新的代码更新我的问题。不知道为什么在抛出错误时它仍然没有显示表单中的错误。我可以看到它位于帐户 > 计算 > 表单 > 错误 > 错误 > 名称下的开发工具中。将错误嵌套在错误中,将错误归咎于 Laravel。大声笑

以上是关于错误时更新 Vue 中的计算属性(表单)?的主要内容,如果未能解决你的问题,请参考以下文章

表单修饰符自定义指令计算属性侦听器过滤器生命周期

表单修饰符自定义指令计算属性侦听器过滤器生命周期

未使用 Vuex 中的计算属性注册突变

Vue计算属性

使用 Vuex 在 Vue.js 中的计算属性上未从观察者更新数据变量

vue的计算属性