¿Existe una forma adecuada de restablecer los datos iniciales de un componente en vuejs?

92

Tengo un componente con un conjunto específico de datos iniciales:

data: function (){
    return {
        modalBodyDisplay: 'getUserInput', // possible values: 'getUserInput', 'confirmGeocodedValue'
        submitButtonText: 'Lookup', // possible values 'Lookup', 'Yes'
        addressToConfirm: null,
        bestViewedByTheseBounds: null,
        location:{
            name: null,
            address: null,
            position: null
        }
}

Estos son datos para una ventana modal, por lo que cuando se muestre, quiero que comience con estos datos. Si el usuario cancela desde la ventana, quiero restablecer todos los datos a esto.

Sé que puedo crear un método para restablecer los datos y simplemente establecer manualmente todas las propiedades de los datos a su original:

reset: function (){
    this.modalBodyDisplay = 'getUserInput';
    this.submitButtonText = 'Lookup';
    this.addressToConfirm = null;
    this.bestViewedByTheseBounds = null;
    this.location = {
        name: null,
        address: null,
        position: null
    };
}

Pero esto parece realmente descuidado. Significa que si alguna vez hago un cambio en las propiedades de datos del componente, tendré que asegurarme de recordar actualizar la estructura del método de reinicio. Eso no es absolutamente horrible ya que es un pequeño componente modular, pero hace que la parte de optimización de mi cerebro grite.

La solución que pensé que funcionaría sería tomar las propiedades de los datos iniciales en un readymétodo y luego usar esos datos guardados para restablecer los componentes:

data: function (){
    return {
        modalBodyDisplay: 'getUserInput', 
        submitButtonText: 'Lookup', 
        addressToConfirm: null,
        bestViewedByTheseBounds: null,
        location:{
            name: null,
            address: null,
            position: null
        },
        // new property for holding the initial component configuration
        initialDataConfiguration: null
    }
},
ready: function (){
    // grabbing this here so that we can reset the data when we close the window.
    this.initialDataConfiguration = this.$data;
},
methods:{
    resetWindow: function (){
        // set the data for the component back to the original configuration
        this.$data = this.initialDataConfiguration;
    }
}

Pero el initialDataConfigurationobjeto está cambiando junto con los datos (lo cual tiene sentido porque en el método de lectura nuestro initialDataConfigurationestá obteniendo el alcance de la función de datos.

¿Existe alguna forma de obtener los datos de configuración inicial sin heredar el alcance?

¿Estoy pensando demasiado en esto y hay una manera mejor / más fácil de hacer esto?

¿La codificación de los datos iniciales es la única opción?

Chris Schmitz
fuente
¿Está utilizando v-show o v-if para mostrar el modal?
Rwd
Estoy usando bootstrap para el CSS, así que estoy usando su modal integrado que aprovecha jquery para mostrar y ocultar. Entonces, esencialmente, la parte de la ventana del componente siempre está ahí, simplemente oculta.
Chris Schmitz

Respuestas:

125
  1. extraer los datos iniciales en una función fuera del componente
  2. use esa función para establecer los datos iniciales en el componente
  3. reutilice esa función para restablecer el estado cuando sea necesario.

// outside of the component:
function initialState (){
  return {
    modalBodyDisplay: 'getUserInput', 
    submitButtonText: 'Lookup', 
    addressToConfirm: null,
    bestViewedByTheseBounds: null,
    location:{
      name: null,
      address: null,
      position: null
    }
  }
}

//inside of the component:
data: function (){
    return initialState();
} 


methods:{
    resetWindow: function (){
        Object.assign(this.$data, initialState());
    }
}

Linus Borg
fuente
5
Eso lo hizo. ¡Gracias! Hice una pequeña edición en la respuesta, pero solo porque un componente vue requiere una función devuelta para datos en lugar de solo un objeto. Su concepto de respuestas definitivamente funciona y es correcto, la edición es solo para tener en cuenta cómo vuejs maneja los componentes.
Chris Schmitz
3
Tiene razón acerca de la función para la propiedad de datos, eso fue lo que yo estaba siendo descuidado. Gracias por editar.
Linus Borg
13
Ahora da un error:[Vue warn]: Avoid replacing instance root $data. Use nested data properties instead.
Sankalp Singha
34
@SankalpSingha Vue 2.0 ya no te permite hacer eso. Puede usar Object.assignen su lugar. Aquí está el código de trabajo: codepen.io/CodinCat/pen/ameraP?editors=1010
CodinCat
3
Para este problema - [Vue warn]: Evite reemplazar la raíz de instancia $ data. Utilice propiedades de datos anidados en su lugar, intente esto. $ Data.propName = "new value";
Stanislav Ostapenko
32

Para restablecer el componente dataen una instancia de componente actual, puede intentar esto:

Object.assign(this.$data, this.$options.data())

En privado, tengo un componente modal abstracto que utiliza espacios para llenar varias partes del diálogo. Cuando el modal personalizado envuelve ese modal abstracto, los datos referidos en las ranuras pertenecen al ámbito del componente principal . Aquí está la opción del modal abstracto que restablece los datos cada vez que se muestra el modal personalizado (código ES2015):

watch: {
    show (value) { // this is prop's watch
      if(value) {
        Object.assign(this.$parent.$data, this.$parent.$options.data())
      }
    }
}

Por supuesto, puede ajustar su implementación modal; lo anterior también puede ejecutarse en algún cancelgancho.

Tenga en cuenta que $parentno se recomienda la mutación de opciones de niño, sin embargo, creo que puede estar justificado si el componente principal solo personaliza el modal abstracto y nada más.

gertas
fuente
1
Esta técnica ahora da una advertencia de VueJS; ver stackoverflow.com/questions/40340561/…
Kivi Shapiro
7
Precaución, esto no vincula el contexto en data. Entonces, si está utilizando thisen su datamétodo, puede aplicar el contexto con:Object.assign(this.$data, this.$options.data.apply(this))
Si no es
¿Cuál es la ventaja de esta forma frente a location.reload ()?
Carlos
29

Precaución, Object.assign(this.$data, this.$options.data())no vincula el contexto a datos ().

Entonces usa esto:

Object.assign(this.$data, this.$options.data.apply(this))

cc esta respuesta estaba originalmente aquí

roli roli
fuente
3

Si le molestan las advertencias, este es un método diferente:

const initialData = () => ({})

export default {
  data() {
    return initialData();
  },
  methods: {
    resetData(){
      const data = initialData()
      Object.keys(data).forEach(k => this[k] = data[k])
    }
  }
}

No hay necesidad de meterse con $ data.

srmico
fuente
2

Tuve que restablecer los datos al estado original dentro de un componente secundario, esto es lo que funcionó para mí:

Componente padre, llamando al método del componente hijo:

     <button @click="$refs.childComponent.clearAllData()">Clear All</button >

     <child-component ref='childComponent></child-component>

Componente hijo:

  1. definir datos en una función externa,
  2. Asignar el objeto de datos a una función externa
  3. definir el método clearallData () que será invocado por el componente principal

    function initialState() {
       return { 
         someDataParameters : '',
         someMoreDataParameters: ''
              }
      }
    
    export default {
       data() {
        return initialState();
      },
        methods: {
      clearAllData() {
      Object.assign(this.$data, initialState());
    },
    
Armin
fuente