当前位置: 动力学知识库 > 问答 > 编程问答 >

javascript - VueJS2 with vue-resource creates infinite loop....?

问题描述:

I am using vue-resource with vuejs2

I have built a few components for some of my models.... in this case, I am using retailerOrder which has a one to many relationship with BillOfLadings.

The following code throws NO error and does NOT cause an infinite loop.

I replicated functionality in two main files... these are the ModeratorTrait.js (which is a Vue mixin) and the ModalTrait.js (which is also a Vue mixin)

The ONLY function giving me problems is the update() method in the ModalTrait.js file.

I've tried using...

this.$http.put()

this.$http.patch()

this.resource.update()

and they all give me the same runtime error of hitting an infinite loop (too much recursion error)

I am racking my brain because the update() method in the ModeratorTrait.js works perfectly fine. And the this.$http and the this.resource (except in the update() method) in ModalTrait.js ALSO work perfectly fine!!!!

It is only that one issue!!!

Please help!!

retailer-orders/Moderator.vue

<div>

<button v-if="! showCreateForm"

@click="enableForm()"

class="btn btn-success btn-xl"

>

Create a New {{ modelName }}

</button>

<div v-if="showCreateForm">

New {{ modelName }}

<!--CLIENT_ID-->

<div class="form-group">

<label for="client_id">Client:</label>

<select class="form-control"

id="client_id"

v-model="selectedRetailerOrder.client_id"

v-on:change="loadRetailers()"

>

<option v-for="client in clients"

v-bind:value="client.id"

>

{{ client.name }}

</option>

</select>

</div>

<!--RETAILER_ID-->

<div class="form-group"

v-show="retailers.length"

>

<label for="retailer_id">Retailer:</label>

<select id="retailer_id"

class="form-control"

v-model="selectedRetailerOrder.retailer_id"

>

<option v-for="retailer in retailers"

v-bind:value="retailer.id"

>

{{ retailer.name }}

</option>

</select>

</div>

<!--PO_NUMBER-->

<div class="form-group">

<label for="po_number">PO #:</label>

<input type="text"

class="form-control"

id="po_number"

v-model="selectedRetailerOrder.po_number"

required

>

</div>

<!--PO_DATE-->

<div class="form-group">

<label for="po_date">PO Date:</label>

<input type="text"

class="form-control"

id="po_date"

v-model="selectedRetailerOrder.po_date"

required

>

</div>

<!--PO_DATE-->

<div class="form-group">

<label for="po_mab_date">PO MABD:</label>

<input type="text"

class="form-control"

id="po_mab_date"

v-model="selectedRetailerOrder.po_mab_date"

required

>

</div>

<!--NET_AMOUNT-->

<div class="form-group">

<label for="net_amount">Net:</label>

<div class="input-group">

<span class="input-group-addon">$</span>

<input type="text"

class="form-control"

id="net_amount"

v-model="selectedRetailerOrder.net_amount"

required

>

</div>

</div>

<!--TAX_AMOUNT-->

<div class="form-group">

<label for="tax_amount">Tax:</label>

<div class="input-group">

<span class="input-group-addon">$</span>

<input type="text"

class="form-control"

id="tax_amount"

v-model="selectedRetailerOrder.tax_amount"

required

>

</div>

</div>

<!--TOTAL_AMOUNT-->

<div class="form-group">

<label for="total_amount">Total Amount:</label>

<div class="input-group">

<span class="input-group-addon">$</span>

<input type="text"

class="form-control"

id="total_amount"

v-model="selectedRetailerOrder.total_amount"

required

>

</div>

</div>

<!--UPDATE-->

<button class="btn btn-block btn-primary"

type="submit"

v-show="editMode"

@click.prevent="update()"

>

Update RetailerOrder

</button>

<!--CREATE-->

<button class="btn btn-block btn-primary"

type="submit"

v-show="!editMode"

@click.prevent="create()"

>

Create RetailerOrder

</button>

<!--CANCEL-->

<button class="btn btn-block btn-danger"

type="submit"

@click.prevent="disableForm()"

>

Cancel

</button>

</div>

</div>

import eventBus from './../../../events/eventBus';

import APITrait from './../../../mixins/APITrait';

import ModeratorTrait from './../../../mixins/ModeratorTrait';

export default {

mixins: [

APITrait,

ModeratorTrait,

],

data() {

return {

selectedRetailerOrder: {},

clients: {},

retailers: {},

}

},

mounted() {

this.setResourceUri('/api/admin/retailer-orders');

this.setModelName('RetailerOrder');

this.fetchClientsAndRetailers();

},

methods: {

fetchClientsAndRetailers() {

var vm = this;

this.$http.get('/api/admin/clients').then(function(response) {

// got 200

vm.clients = response.data;

}, function(response) {

// failed

});

},

loadRetailers(){

var vm = this;

var client = this.clients.filter(function(client) {

return client.id == vm.selectedRetailerOrder.client_id;

});

this.retailers = client[0].retailers;

}

},

}

These "Moderator" components use a few mixins, the eventBus, APITrait and Moderator Trait.

Moderator Trait

/js/mixins/ModeratorTrait.js

import eventBus from './../events/eventBus';

export default {

data() {

return {

showForm: false,

editMode: false,

}

},

methods: {

enableForm() {

this.showForm = true;

this.$data[this.dataModel] = {

active: true,

};

},

disableForm() {

this.showForm = false;

this.editMode = false;

this.$data[this.dataModel] = {};

eventBus.$emit('moderator-form-disabled');

},

create() {

var vm = this;

var model = this.$data[this.dataModel];

this.resource.save(model).then(function(response) {

eventBus.$emit('model-created', {

type: vm.modelName,

model: response.data

});

swal('Saved', 'This ' + vm.modelName + ' has been saved.', 'success');

}, function(response) {

swal('Error', 'Could not be saved..', 'error');

});

},

update(model) {

var vm = this;

var model = this.$data[this.dataModel];

this.resource.update({id: model.id}, model).then(function(response) {

// Success

eventBus.$emit('model-updated', {type: vm.modelName, model: response.data});

swal('Updated', 'This ' + vm.modelName + ' has been updated.', 'success');

}, function (response) {

swal('Error', 'Changes could not be saved..', 'error');

});

},

processModelSelectedEvent(data) {

if (data.type != this.modelName)

return false;

this.$data[this.dataModel] = data.model;

this.editMode = true;

},

processModelCreatedEvent(data) {

if (data.type != this.modelName)

return false;

this.editMode = false;

this.showForm = false;

this.$data[this.dataModel] = {};

},

processModelUpdatedEvent(data) {

this.processModelCreatedEvent(data);

},

processModelDeletedEvent(data) {

if (data.type != this.modelName)

return false;

// get this selectedModel

var model = this.$data[this.dataModel];

if (data.model.id == model.id)

{

this.editMode = false;

this.showForm = false;

this.$data[this.dataModel] = {};

}

}

},

computed: {

showCreateForm() {

return this.showForm || this.editMode;

},

isNewModel() {

return ( this.$data[this.dataModel].id != null && this.$data[this.dataModel].id != 0 )

}

},

created() {

eventBus.$on('show-form-clicked', this.enableForm);

eventBus.$on('model-selected', this.processModelSelectedEvent);

eventBus.$on('model-created', this.processModelCreatedEvent);

eventBus.$on('model-updated', this.processModelCreatedEvent);

eventBus.$on('model-deleted', this.processModelDeletedEvent);

},

beforeDestroy() {

eventBus.$off('show-form-clicked', this.enableForm);

eventBus.$off('model-selected', this.processModelSelectedEvent);

eventBus.$off('model-created', this.processModelCreatedEvent);

eventBus.$off('model-updated', this.processModelCreatedEvent);

eventBus.$off('model-deleted', this.processModelDeletedEvent);

}

}

EventBus

/js/events/eventBus.js

import Vue from 'vue';

var eventBus = new Vue();

export default eventBus;

and the last mixin is:

APITrait

/js/mixins/APITrait.js

import eventBus from './../events/eventBus';

export default {

data() {

return {

resource: null,

resourceUri: "",

modelName: "",

dataModel: "",

}

},

methods: {

setResourceUri(uri) {

this.resourceUri = uri;

this.resource = this.$resource(uri + '{/id}');

},

setModelName(name) {

this.modelName = name;

this.dataModel = 'selected' + name;

},

toUnderscore(stringVar) {

var replaced = stringVar.replace(/[a-z][A-Z]/g, function(str, offset) {

return str[0].toLowerCase() + '_' + str[1].toLowerCase();

});

return replaced[0].toLowerCase() + replaced.slice(1);

},

}

}

All of these functions work perfectly and they allow me to write very clear and conside model-name/Moderator.vue files to manage the forms for performing CRUD operations on these models.....

The error comes in here.....

For the Bill of ladings, I have it come through a modal....

BolModal.vue

<div>

<!-- Modal -->

<div class="modal fade"

id="adminRetailerBillOfLadingModal"

tabindex="-1"

role="dialog"

aria-labelledby="myModalLabel"

>

<div class="modal-dialog" role="document">

<div class="modal-content">

<div class="modal-header">

<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>

<h4 class="modal-title" v-if="!editMode" id="myModalLabel">Attach a {{ modelName }} to order</h4>

<h4 class="modal-title" v-if="editMode" id="myModalLabel">Review {{ modelName }}</h4>

</div>

<div class="modal-body">

<!--<form>-->

<div class="form-group"

v-if="parentIsLoaded"

>

<label for="retailer_purchase_order_id">Retailer:</label>

<input type="text"

class="form-control"

disabled

id="retailer_id"

v-bind:value="parent_data.model.retailer.name"

required

>

</div>

<div class="form-group"

v-if="parentIsLoaded"

>

<label for="retailer_purchase_order_id">Retailer PO:</label>

<input type="text"

class="form-control"

disabled

id="retailer_purchase_order_id"

v-bind:value="parent_data.model.po_number"

required

>

</div>

<!--PROVIDER_ID-->

<div class="form-group"

v-show="providers.length"

>

<label for="provider_id">Provider:</label>

<select id="provider_id"

class="form-control"

v-model="selectedRetailerBillOfLading.provider_id"

>

<option v-for="provider in providers"

v-bind:value="provider.id"

>

{{ provider.name }}

</option>

</select>

</div>

<!--BOL_NUMBER-->

<div class="form-group">

<label for="bol_number">BOL #:</label>

<input type="text"

class="form-control"

id="bol_number"

v-model="selectedRetailerBillOfLading.bol_number"

required

>

</div>

<!--SHIPPED_DATE-->

<div class="form-group">

<label for="shipped_date">Shipped Date:</label>

<input type="text"

class="form-control"

id="shipped_date"

v-model="selectedRetailerBillOfLading.shipped_date"

required

>

</div>

<div class="input-group">

<label class="input-group-btn">

<span class="btn btn-primary">

Browse&hellip;

<input type="file"

style="display: none;"

id="attachmentFile"

name="attachmentFile"

>

</span>

</label>

<input type="text" class="form-control" readonly>

</div>

<!--</form>-->

</div>

<div class="modal-footer">

<!--DELETE-->

<button class="btn btn-danger"

data-dismiss="modal"

type="submit"

v-show="editMode"

@click.prevent="removeModel()"

>

Delete

</button>

<!--CANCEL-->

<button class="btn btn-default"

data-dismiss="modal"

type="submit"

@click.prevent="disableModal()"

>

Cancel

</button>

<!--UPDATE-->

<button class="btn btn-primary"

type="submit"

v-show="editMode"

@click.prevent="update()"

>

Update BOL

</button>

<!--SAVE-->

<button class="btn btn-primary"

type="submit"

v-show="!editMode"

@click.prevent="create()"

>

Attach

</button>

<!--<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>-->

<!--<button type="button" class="btn btn-primary">Save changes</button>-->

</div>

</div>

</div>

</div>

</div>

import eventBus from './../../../events/eventBus';

import APITrait from './../../../mixins/APITrait';

import ModalTrait from './../../../mixins/ModalTrait';

export default {

mixins: [

ModalTrait,

APITrait,

],

data() {

return {

selectedRetailerBillOfLading: {},

providers: {},

}

},

mounted() {

this.setResourceUri('/api/admin/retailer-bols');

this.setModelName('RetailerBillOfLading');

this.setModalName('RetailerBillOfLading');

this.fetchProviders();

},

methods: {

fetchProviders() {

var vm = this;

this.$http.get('/api/admin/providers').then(function(response) {

// got 200

vm.providers = response.data;

}, function (response) {

// failed

});

},

},

computed: {

parentIsLoaded() {

if (this.parent_data == null)

return false;

if (this.parent_data.model == null)

return false;

return true;

}

},

}

As you can see, this modal uses another new Trait (instead of the ModeratorTrait, because I want to send relational data (since the Modals will be for handling children models of the parent)

That mixin is below:

/js/mixins/ModalTrain.js

import eventBus from './../events/eventBus';

export default {

data() {

return {

isVisible: false,

modalId: "",

editMode: false,

parent_data: {}

}

},

computed: {

showModal() {

return this.show && this.isVisible;

},

},

methods: {

setModalName(name) {

this.modalId = '#admin' + name + 'Modal';

},

enableModal() {

this.isVisible = true;

$(this.modalId).modal('show');

},

disableModal() {

this.isVisible = false;

this.editMode = false;

$(this.modalId).modal('hide');

},

processLoadCreateModal(data) {

if (data.type != this.modelName)

return false;

this.editMode = false;

this.$data[this.dataModel] = {};

this.parent_data = data.parent_data;

for (var prop in data) {

if (data.hasOwnProperty(prop) && prop != "parent_data") {

this.$data[this.dataModel][prop] = data[prop];

}

}

this.enableModal();

},

processLoadEditModal(data) {

if (data.type != this.modelName)

return false;

this.editMode = true;

this.$data[this.dataModel] = data.model;

this.parent_data = data.parent_data;

this.enableModal();

},

create() {

var vm = this;

var model = this.$data[this.dataModel];

// Build Form Request Object

var formData = new FormData();

// Add in current model as the base

for (var property in this.$data[this.dataModel]) {

if (this.$data[this.dataModel].hasOwnProperty(property)) {

formData.append(property, this.$data[this.dataModel][property]);

}

}

// Add in any attachments

var form = document.querySelector('#attachmentFile');

var file = form.files[0];

formData.append('attachment', file);

// Submit the request

this.$http.post(this.resourceUri, formData, {

}).then(function(response) {

eventBus.$emit('model-created', {

type: vm.modelName,

model: response.data

});

swal('Saved', 'This ' + vm.modelName + ' has been saved.', 'success');

eventBus.$emit('child-created', {

type: vm.parent_data.name,

parent_id: vm.parent_data.model.id,

child_model: vm.$data[vm.dataModel],

child_name: vm.modelName

});

this.disableModal();

}, function(response) {

swal('Error', 'Could not be saved..', 'error');

});

},

update() {

var vm = this;

var model = this.$data[this.dataModel];

ERROR HERE::: This File Continued.....

//

//

// THIS IS THE PART THAT KEEPS GIVING ME THE ERROR!!!!

//

//

this.$http.put({id: model.id}, model).then(function(response) {

alert('success');

// Success

// eventBus.$emit('model-updated', {type: vm.modelName, model: response.data});

// swal('Updated', 'This ' + vm.modelName + ' has been updated.', 'success');

// eventBus.$emit('child-created', {

// type: vm.parent_data.name,

// parent_id: vm.parent_data.model.id,

// child_model: vm.$data[vm.dataModel],

// child_name: vm.modelName

// });

// this.disableModal();

}, function (response) {

alert('failure');

// swal('Error', 'Changes could not be saved..', 'error');

});

//

//

// ^^^^ The alerts above are never executed...

// The this.$http.put throws an infinite loop...

//

//

},

removeModel() {

var vm = this;

var model = this.$data[this.dataModel];

this.resource.delete({id: model.id}).then(function(response) {

// success

swal('Deleted', 'This '+ vm.modelName + ' has been deleted', 'success');

eventBus.$emit('child-deleted', {

type: vm.parent_data.name,

parent_id: vm.parent_data.model.id,

child_id: vm.$data[vm.dataModel].id,

child_name: vm.modelName,

});

vm.disableModal();

}, function(response) {

// fail

swal('Error', 'Could not be deleted...', 'error');

});

}

},

created() {

eventBus.$on('attach-modal-selected', this.processLoadCreateModal);

eventBus.$on('view-modal-selected', this.processLoadEditModal);

},

beforeDestroy() {

eventBus.$off('attach-modal-selected', this.processLoadCreateModal);

eventBus.$off('view-modal-selected', this.processLoadEditModal);

}

}

The Final bit of code to share is the file loading all of these files... which is then compiled by webpack using gulp (with a Laravel installation to manage the API)

assets\js\retailer-orders.js

require('./bootstrap');

// import eventBus from './events/eventBus';

// var eventBus = new Vue();

Vue.component(

'admin-retailer-orders-moderator',

require('./components/admin/retailer-orders/Moderator.vue')

);

Vue.component(

'admin-retailer-orders-navigator',

require('./components/admin/retailer-orders/Navigator.vue')

);

Vue.component(

'admin-attachments-bol-modal',

require('./components/admin/attachments/BolModal.vue')

);

$(function(){

$("#po_date").datepicker();

$("#po_mab_date").datepicker();

});

var retailerOrdersApp = new Vue({

el: '#app'

});require('./bootstrap');

// import eventBus from './events/eventBus';

// var eventBus = new Vue();

Vue.component(

'admin-retailer-orders-moderator',

require('./components/admin/retailer-orders/Moderator.vue')

);

Vue.component(

'admin-retailer-orders-navigator',

require('./components/admin/retailer-orders/Navigator.vue')

);

Vue.component(

'admin-attachments-bol-modal',

require('./components/admin/attachments/BolModal.vue')

);

$(function(){

$("#po_date").datepicker();

$("#po_mab_date").datepicker();

});

var retailerOrdersApp = new Vue({

el: '#app'

});

分享给朋友:
您可能感兴趣的文章:
随机阅读: