This commit is contained in:
2019-03-27 23:15:34 +00:00
parent 47043fac71
commit df2e17b1ab
4 changed files with 203 additions and 27 deletions

View File

@@ -14,27 +14,16 @@ TODO CLIENT STUFF
TODO NEXT
End to end action
- The faster I get to a fully working basic level like being able to do data entry and submit to server new or updated records, the faster I can flesh out all the rest
- Code the submit data to server route for update
- Code for new record to the server
GZ VALIDATE
- Add rules for each field type validation
- Is there anything pulled into the validate code directly that is already available off the "v" variable?
- localization etc
Simulate server broken rules so can integrate into ui and rule system
Going to need to handle localized numeric entry formats
DATETIME
- Validation
- after much fuckery it's becoming clear that between the localization requirements and the complexity of server broken rules coming back from the api that I should just use my own validation code
- See here: https://vuetifyjs.com/en/components/forms#form
- And here: https://vuetifyjs.com/en/components/text-fields#custom-validation
- What is needed is a class that returns an array of functions that can be passed to vuetify "rules" property of components
On change each rule is called in turn and if one returns false or a string then it's in an error state
- I also need to add that it scans and or keeps a collection of broken rules that come back from the server and each component checks a rule that checks in turn for server broken rules in last api call
- And my rules object needs to be localized so I guess it should be aware of the locale object and work with it as required
- Should it lazy load error translations? (In as batchy a way as possible?)
- Or, perhaps it's more convenient to cache all possible regular form entry errors since there isn't really that many, perhaps less than a dozen when it comes down to it
- My rules object needs to be coded so I can easily specify a collection of rules appropriate to a form field
- So, for example let's say I have a date input, if I commonly need one to be required and be after or before another field then I should have a single combined rule of
RequiredAndAfterTarget and this method is aggregates both the required and the After rules into a single collection returned
@@ -46,9 +35,16 @@ DON'T code the user options with the currency symbol etc until after it's all be
Locale should fetch those settings the first time it sees they are not present so that they are refreshed upon use and are not stored in localstorage
(or should they be? anyway, can work that out later)
Other fields that are locale dependent
DateTime field next
FIXES REQUIRED
- API get code is incorrectly dealing with expired bearer cert, a 401 is returned and it tries to parse the result as if it succeeded when it really should trigger a login process
- Time zone offset mismatch warning needs expansion, it should only prompt a few times (maybe or find a way to deal with this) and it should offer to change it at the server automatically
- Localize time zone mismatch warning
@@ -160,6 +156,10 @@ Make all fields work according to specs below
- What to do if they edit? Refresh the list but keep the same page location?
TESTING TODO
Localized input and parsing and validation
- Going to need to handle localized numeric entry formats
- Deal with this once form is in good shape and worth testing with different locales
-----------------
TODO AFTER CLIENT block ABOVE:

View File

@@ -93,6 +93,14 @@ export default {
body: JSON.stringify(data)
};
},
fetchPutOptions(data) {
return {
method: "put",
mode: "cors",
headers: this.postAuthorizedHeaders(),
body: JSON.stringify(data)
};
},
fetchGetOptions() {
/* GET WITH AUTH */
return {
@@ -134,6 +142,9 @@ export default {
}
return store.state.apiUrl + apiPath;
},
/////////////////////////////
// ENCODE QUERY STRING
//
buildQuery(obj, sep, eq, name) {
sep = sep || "&";
eq = eq || "=";
@@ -166,6 +177,9 @@ export default {
encodeURIComponent(stringifyPrimitive(obj))
);
},
///////////////////////////////////
// GET DATA FROM API SERVER
//
get(route) {
var that = this;
return new Promise(function(resolve, reject) {
@@ -195,6 +209,49 @@ export default {
}
});
});
},
///////////////////////////////////
// POST / PUT DATA TO API SERVER
//
upsert(route, data) {
var that = this;
return new Promise(function(resolve, reject) {
//determine if this is a new or existing record
var fetchOptions = undefined;
if (data.concurrencyToken) {
fetchOptions = that.fetchPutOptions(data);
} else {
fetchOptions = that.fetchPostOptions(data);
}
fetch(that.APIUrl(route), fetchOptions)
.then(that.status)
.then(that.json)
.then(response => {
//Note: response.error indicates there is an error, however this is not an unusual condition
//it could be validation errors or other general error so we need to treat it here like it's normal
//and let the caller deal with it appropriately
resolve(response);
})
.catch(function(error) {
//fundamental error, can't proceed with this call
var errorMessage =
"API error: UPSERT route =" + route + ", message =" + error.message;
store.commit("logItem", errorMessage);
if (error.message && error.message.includes("401")) {
store.commit(
"logItem",
"User is not authorized, redirecting to login"
);
auth.logout();
router.push("/login");
} else {
//alert("Error: " + errorMessage);
reject(error);
}
});
});
}
//new functions above here

View File

@@ -75,6 +75,46 @@ function getControlLabel(ctrl) {
}
export default {
///////////////////////////////
// SERVER ERRORS
//
Server(v, ref) {
//check if any errors and short circuit if none
//check if this control is mentioned at all and short circuit return false if not
var ctrl = getControl(v, ref);
if(typeof ctrl == 'undefined'){
return false;
}
//It IS in the list of error controls:
//check if this control has been changed at all, I guess being here might mean it has?
//If this control is dirty / was changed from the value that was in it when the server returned the error then remove the error for this control from the server error list and return false
//ELSE if this control is unchanged / not dirty
//return the error(s) properly localized
//IF user modifies field in any way then this rule must be cleared
//Some rules are for the entire object so...???
//maybe need a form control that is just about rules or something
return false;
// // "ErrorRequiredFieldEmpty": "{0} is a required field. Please enter a value for {0}",
// var err = locale.get("ErrorRequiredFieldEmpty");
// var fieldName = getControlLabel(ctrl);
// err = _.replace(err, "{0}", fieldName);
// //lodash replace only replaces first instance so need to do it twice
// err = _.replace(err, "{0}", fieldName);
// return err;
},
///////////////////////////////
// REQUIRED
//

View File

@@ -1,7 +1,7 @@
<template>
<v-layout v-if="this.formReady">
<v-flex>
<form ref="form">
<v-form ref="form">
<v-layout align-center justify-left row wrap>
<v-flex xs12 sm6 lg4 xl3 px-2>
<v-text-field
@@ -26,7 +26,7 @@
v-model="obj.count"
:counter="10"
:label="this.$gzlocale.get('WidgetCount')"
ref="count"
ref="count"
:rules="[this.$gzv.Integer(this,'count'),this.$gzv.Required(this,'count')]"
required
></v-text-field>
@@ -47,7 +47,7 @@
<gz-date-time-picker
:label="this.$gzlocale.get('WidgetStartDate')"
v-model="obj.startDate"
ref="startDate"
ref="startDate"
></gz-date-time-picker>
</v-flex>
@@ -63,24 +63,34 @@
<v-checkbox
v-model="obj.active"
:label="this.$gzlocale.get('Active')"
ref="active"
ref="active"
required
></v-checkbox>
</v-flex>
<v-flex xs12 sm6 lg4 xl3 px-2>
<v-text-field
v-model="obj.roles"
:label="this.$gzlocale.get('WidgetRoles')"
ref="roles"
:rules="[this.$gzv.Integer(this,'roles'),this.$gzv.Required(this,'roles')]"
:error-messages="canHasServerError('roles')"
required
></v-text-field>
</v-flex>
</v-layout>
<v-layout align-center justify-space-around row wrap mt-5>
<v-flex xs1>
<v-btn>one</v-btn>
<v-btn @click="validate">Force validate</v-btn>
</v-flex>
<v-flex xs1>
<v-btn>two</v-btn>
<v-btn>test2</v-btn>
</v-flex>
<v-flex xs1>
<v-btn @click="submit">submit</v-btn>
<v-btn @click="submit">save</v-btn>
</v-flex>
</v-layout>
</form>
</v-form>
</v-flex>
</v-layout>
</template>
@@ -133,10 +143,27 @@ export default {
data() {
return {
obj: {},
serverErrors: {},
formReady: false
};
},
methods: {
getErrorCount() {
return 3;
},
canHasServerError(fieldName) {
if (fieldName == "roles") {
return ["This is an error"];
}
},
validate() {
// this.$refs.form.resetValidation();
// this.$refs.form.validate();
//test to manually insert an error into the field like a server validation error would need to do
//UPDATE: this cannot work because you need to bind to error-messages, not set it directly like here
// this.$refs.roles["error-messages"] = ["This is an error!"];
// this.$refs.roles.error = true;
},
getDataFromApi() {
var url = "Widget/" + this.$route.params.id;
this.$gzapi.get(url).then(res => {
@@ -145,9 +172,61 @@ export default {
},
submit() {
// debugger;
//this.$validator.validateAll();
this.$refs.form.validate();
}
//Submit the form data to the api
//Check for broken rules, do not submit with broken rules
//No broken rules then:
//Gather up the form data into a submitable object (can I just submit the existing object??)
//Post it
//Update the local object with the returned result
//Check the return object for broken rules
var that = this;
var url = "Widget/" + this.$route.params.id;
this.$gzapi
.upsert(url, this.obj)
.then(res => {
if (res.error) {
debugger;
that.serverErrors = res.error;
that.$refs.form.resetValidation();
that.$refs.form.validate();
//example error when submit when there are no roles set at all (blank)
//{"error":{"code":"2200","details":[{"code":"2200","message":"","target":"roles","error":"VALIDATION_FAILED"}],"message":"Object did not pass validation"}}
//todo: integrate validation error into form so user can see it
//User can only submit if no existing errors so should be starting with a clean error free form and then will see validation errors under appropriate fields
//if a user makes a change to a control then that control being changed should remove the rule from the server until the next submit happens
} else {
//Logic for detecing if a post or put: if id then it was a post, if no id then it was a put
if (res.id) {
//Handle "post" of new record
that.obj = res.data;
} else {
//Handle "put" of an existing record
that.obj.concurrencyToken = res.data.concurrencyToken;
}
}
})
.catch(function(error) {
//we should be here if it was a gross error of some kind not a mild one like validation but more like if the server doesn't exist or something I guess
console.log(error);
alert("Houston, we have a problem");
});
//example from login form
// if (this.input.username != "" && this.input.password != "") {
// auth
// .authenticate(this.input.username, this.input.password)
// .then(() => {
// this.$router.replace({ name: "home" });
// })
// .catch(function(error) {
// /* xeslint-disable-next-line */
// //console.log(error);
// alert("login failed: " + error);
// });
// }
} //end of submit()
}
};
</script>