KO validation: model.errors is undefined - javascript

I have this model
var MarketResearch = function (data) {
var self = this;
self.Validate = function() {
if (!self.isValid()) {
self.errors.showAllMessages();
return false;
}
return true;
};
this.id = data ? data.id : 0;
this.city = ko.observable(data ? data.city : '').extend({ required: true });
this.since = ko.observable(data ? data.since : '').extend({ required: true });
this.title = ko.observable(data ? data.title : '').extend({ required: true });
}
Here is the view:
function onDocumentReady() {
koValidationConfig()
// initializeDataPickers(market);
// createCkEditor('market_editor');
ko.applyBindings(market, document.getElementById("market-form"));
}
var market = new MarketResearch(null);
function onSaveMarketClicked() {
market.errors.showAllMessages();
}
function koValidationConfig() {
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.configure({
// registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
decorateInputElement: true,
});
ko.validation.registerExtenders();
}
I have some required fields here. When I put nothing in the fields it displays "this field is required" and colors the form elements.
But market.errors is always undefined, so I can't check if the form is valid!
market.errors.showAllMessages();
Doesn't work too.
Ko.validation is defined, I checked.
What's wrong?

ko.validation adds an errors property to observables, not models. You also need to use .extend on an observable to enable validation.

Related

Accessing a variable in vuejs or javascript

I have this javascript variable, I'm using vuejs.
when I try to access an array field to validate a form, the chrome dev tools returns an error.
var checkItems = {contact_email: "", contact_name: "", contact_phone: "", message: "", subject_id: null, …}
I try to access this way:
if(checkItems.contact_email)
alert("email required");
This is the error:
Property or method "contact_email" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option
If the form fields are empty, I want to detect individually which one is empty and send a custom error for each one, for example:
Name field is empty
The email field is empty
This is my vuejs code:
var locale = '{{ $lang }}'; //'es-ES',
var V_Alerts = new Vue({
el : '#v-alerts',
data : {
types : ['danger', 'warning', 'success', 'info'],
alerts : [
]
},
methods : {
add : function(type, content, opts)
{
this.alerts.push({
type : type,
content : content,
opts : opts
});
},
addSuccess : function(content, opts){
this.add('success',content, opts)
}
}
});
var new_ticket = new Vue({
el : '#create_ticket',
data : {
uploading : false,
submitting : false,
subject_id : null,
message : '',
errors: [],
},
methods : {
validation: function (params)
{
return {
contact_email : IsEmail(params.contact_email),
contact_name : !!params.contact_name.trim(),
message : !!params.message.trim(),
subject_id : params.subject_id && !!params.subject_id.trim(),
captcha : params.captcha !== 0
}
},
isValid : function(params)
{
var validation = this.validation(params);
return Object.keys(validation).every(function (key) {
return validation[key];
});
},
restart : function()
{
this.uploading = false;
this.submitting = false;
this.subject_id = null;
this.$refs.subjects.restart();
this.$refs.uploads.restart();
$('#message').text('');
$('#order_number').val('');
$('#contact_email').val('');
$('#contact_name').val('');
$('#contact_phone').val('');
$('#message').val('');
grecaptcha.reset();
},
onSubjectSelect : function(subject_id){
this.subject_id = subject_id;
},
_onSubjectsLoaded : function(subjects){
emitOnWidgetContentChanged();
},
createTicket : function(e)
{
var params = {
contact_email : $('#contact_email').val(),
contact_name : $('#contact_name').val(),
contact_phone : $('#contact_phone').val(),
message : $('#message').val(),
subject_id : this.subject_id,
message_files : this.$refs.uploads.completed_ids.join(','),
captcha : grecaptcha.getResponse()
};
#if (Input::has('public_token'))
params.public_token = '{{ Input::get('public_token') }}';
#endif
if ($('#order_number').val() != '')
params.contact_orders = $('#order_number').val();
if (!this.isValid(params))
{
var checkItems = params;
if(checkItems.contact_email)
alert("email");
alert('{{ addslashes(trans('common.empty_or_error_input')) }}');
return;
}
this.submitting = true;
// only ie11 need this manuall
params._token = '{!! csrf_token() !!}';
AjaxServices.post('createTicket', params, function(error, result)
{
this.submitting = false;
if (error)
{
alert('{{ addslashes(trans('accounts/tickets.error_creating_ticket')) }}');
grecaptcha.reset();
}
else
{
alert('#'+ result.ticket_id +' - {{ addslashes(trans('accounts/tickets.new_ticket_created_ok')) }} :)');
V_Alerts.addSuccess('#'+ result.ticket_id +' - {{ addslashes(trans('accounts/tickets.new_ticket_created_ok')) }}');
this.restart();
emitOnWidgetContentChanged();
}
}.bind(this));
},
onUploadComplete : function(ids){
this.uploading = false;
emitOnWidgetContentChanged();
},
onUploadStarted : function(){
this.uploading = true;
setTimeout(emitOnWidgetContentChanged,1);
},
onItemDeleted : function(){
},
onFilesSelected : function(){
}
}
});
function IsEmail(email) {
var regex = /^([a-zA-Z0-9_.+-])+\#(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
return regex.test(email);
}
$(document).ready(function(){
//new_ticket.restart();
});
You are not utilizing Vue properly. The error you are receiving stems from not defining your properties in the data object. You cant just return them as you are in the validation method because Vue is looking for a data object called contact_email, or a method called contact_email() or even a computed property called contact_email.
data : {
// define your properties here
contact_email: '';
},
methods: {
yourMethod: function(){
//modify your properties here
this.contact_email: IsEmail(params.contact_email)
}
}

Bootstrap-treeview not setting state with "checkNode" method

I'm trying to update the parents and children checked inputs using bootstrap-treeview, but when I use the method "checkNode", the state of the node doesn't change at all.
var trucks = $('#trucks').treeview({
level: 3,
showCheckbox: true,
selectable: false,
highlightSelected: false,
data: getTree()
}).on('nodeChecked', function (event, node){
var childrenNodes = __getChildren(node);
childrenNodes.forEach(function(n){
$(trucks).treeview('checkNode', [ n.nodeId, { silent: true } ]);
console.log(n.state.checked);
});
});
function __getChildren(node) {
if (node.nodes === undefined) return [];
var childrenNodes = node.nodes;
node.nodes.forEach(function(n) {
childrenNodes = childrenNodes.concat(__getChildren(n));
});
return childrenNodes;
}
The input is checked normally, but console output says the state is "false"
Anyone have an a idea of what I'm doing wrong?

javascript: Alter the output of a function to the specified decimal place

I am not very good with my javascript but recently needed to work with a library to output an aggregated table. Was using fin-hypergrid.
There was a part where I need to insert a sum function (rollups.sum(11) in this example)to an object so that it can compute an aggregated value in a table like so:
aggregates = {Value: rollups.sum(11)}
I would like to change this value to return 2 decimal places and tried:
rollups.sum(11).toFixed(2)
However, it gives the error : "rollups.sum(...).toFixed is not a function"
If I try something like:
parseFloat(rollups.sum(11)).toFixed(2)
it throws the error: "can't assign to properties of (new String("NaN")): not an object"
so it has to be a function object.
May I know if there is a way to alter the function rollups.sum(11) to return a function object with 2 decimal places?
(side info: rollups.sum(11) comes from a module which gives:
sum: function(columnIndex) {
return sum.bind(this, columnIndex);
}
)
Sorry I could not post sample output here due to data confidentiality issues.
However, here is the code from the example I follow. I basically need to change rollups.whatever to give decimal places. The "11" in sum(11) here refers to a "column index".
window.onload = function() {
var Hypergrid = fin.Hypergrid;
var drillDown = Hypergrid.drillDown;
var TreeView = Hypergrid.TreeView;
var GroupView = Hypergrid.GroupView;
var AggView = Hypergrid.AggregationsView;
// List of properties to show as checkboxes in this demo's "dashboard"
var toggleProps = [{
label: 'Grouping',
ctrls: [
{ name: 'treeview', checked: false, setter: toggleTreeview },
{ name: 'aggregates', checked: false, setter: toggleAggregates },
{ name: 'grouping', checked: false, setter: toggleGrouping}
]
}
];
function derivedPeopleSchema(columns) {
// create a hierarchical schema organized by alias
var factory = new Hypergrid.ColumnSchemaFactory(columns);
factory.organize(/^(one|two|three|four|five|six|seven|eight)/i, { key: 'alias' });
var columnSchema = factory.lookup('last_name');
if (columnSchema) {
columnSchema.defaultOp = 'IN';
}
//factory.lookup('birthState').opMenu = ['>', '<'];
return factory.schema;
}
var customSchema = [
{ name: 'last_name', type: 'number', opMenu: ['=', '<', '>'], opMustBeInMenu: true },
{ name: 'total_number_of_pets_owned', type: 'number' },
{ name: 'height', type: 'number' },
'birthDate',
'birthState',
'employed',
{ name: 'income', type: 'number' },
{ name: 'travel', type: 'number' }
];
var peopleSchema = customSchema; // or try setting to derivedPeopleSchema
var gridOptions = {
data: people1,
schema: peopleSchema,
margin: { bottom: '17px' }
},
grid = window.g = new Hypergrid('div#json-example', gridOptions),
behavior = window.b = grid.behavior,
dataModel = window.m = behavior.dataModel,
idx = behavior.columnEnum;
console.log('Fields:'); console.dir(behavior.dataModel.getFields());
console.log('Headers:'); console.dir(behavior.dataModel.getHeaders());
console.log('Indexes:'); console.dir(idx);
var treeView, dataset;
function setData(data, options) {
options = options || {};
if (data === people1 || data === people2) {
options.schema = peopleSchema;
}
dataset = data;
behavior.setData(data, options);
idx = behavior.columnEnum;
}
// Preset a default dialog options object. Used by call to toggleDialog('ColumnPicker') from features/ColumnPicker.js and by toggleDialog() defined herein.
grid.setDialogOptions({
//container: document.getElementById('dialog-container'),
settings: false
});
// add a column filter subexpression containing a single condition purely for demo purposes
if (false) { // eslint-disable-line no-constant-condition
grid.getGlobalFilter().columnFilters.add({
children: [{
column: 'total_number_of_pets_owned',
operator: '=',
operand: '3'
}],
type: 'columnFilter'
});
}
window.vent = false;
//functions for showing the grouping/rollup capabilities
var rollups = window.fin.Hypergrid.analytics.util.aggregations,
aggregates = {
totalPets: rollups.sum(2),
averagePets: rollups.avg(2),
maxPets: rollups.max(2),
minPets: rollups.min(2),
firstPet: rollups.first(2),
lastPet: rollups.last(2),
stdDevPets: rollups.stddev(2)
},
groups = [idx.BIRTH_STATE, idx.LAST_NAME, idx.FIRST_NAME];
var aggView, aggViewOn = false, doAggregates = false;
function toggleAggregates() {
if (!aggView){
aggView = new AggView(grid, {});
aggView.setPipeline({ includeSorter: true, includeFilter: true });
}
if (this.checked) {
grid.setAggregateGroups(aggregates, groups);
aggViewOn = true;
} else {
grid.setAggregateGroups([], []);
aggViewOn = false;
}
}
function toggleTreeview() {
if (this.checked) {
treeView = new TreeView(grid, { treeColumn: 'State' });
treeView.setPipeline({ includeSorter: true, includeFilter: true });
treeView.setRelation(true, true);
} else {
treeView.setRelation(false);
treeView = undefined;
delete dataModel.pipeline; // restore original (shared) pipeline
behavior.setData(); // reset with original pipeline
}
}
var groupView, groupViewOn = false;
function toggleGrouping(){
if (!groupView){
groupView = new GroupView(grid, {});
groupView.setPipeline({ includeSorter: true, includeFilter: true });
}
if (this.checked){
grid.setGroups(groups);
groupViewOn = true;
} else {
grid.setGroups([]);
groupViewOn = false;
}
}
you may try:
(rollups.sum(11)).toFixed(2)
enclosing number in parentheses seems to make browser bypass the limit that identifier cannot start immediately after numeric literal
edited #2:
//all formatting and rendering per cell can be overridden in here
dataModel.getCell = function(config, rendererName) {
if(aggViewOn)
{
if(config.columnName == "total_pets")
{
if(typeof(config.value) == 'number')
{
config.value = config.value.toFixed(2);
}
else if(config.value && config.value.length == 3 && typeof(config.value[1]) == 'number')
{
config.value = config.value[1].toFixed(2);
}
}
}
return grid.cellRenderers.get(rendererName);
};

Meteor Method.call issue in jquery-validation

I have a form to change password. I need to validate the old password. But jquery addMethod is always return false in Meteor.call. How to make it workable. Or is there any way? My bellow code will be more details about my issue.
$.validator.addMethod( 'checkPassword', ( oldpassword ) => {
var digest = Package.sha.SHA256(oldpassword);
Meteor.call('checkPassword', digest, function(err, result) {
var res = result.error != null; // even if this is "true", error message is visible.
return res;
});
});
$( "#changepassword" ).validate({
rules: {
oldpassword: {
required: true,
checkPassword: true
}
},
messages: {
oldpassword: {
required: "Please enter your Old Password",
checkPassword: "Password doesnt match!!!" //this message is visible all the time.
} }
});
Here is my method call
Meteor.methods({
checkPassword: function(digest){
if (Meteor.isServer) {
if (this.userId) {
var user = Meteor.user();
var password = {digest: digest, algorithm: 'sha-256'};
var result = Accounts._checkPassword(user, password);
return result;
}
}
}
});
here the meteor package

Knockout Validation length is always 0

I am new to using knockout and I am trying to get the validation plug-in to work. However, I tried ViewModel.errors().length == 0 but it is always zero
when i check the isValid - I always get true.
Here is the rest of my code, please help.
define(['knockout','knockout-validation', 'services/changeup', 'services/currencies', 'plugins/router'], function (ko, validation, changeup, currencies, router) {
ko.validation.configure({
insertMessages: true,
decorateElement: true,
errorElementClass: 'error',
errorMessageClass: 'help-inline '
});
var ctor = function () {
this.amount = ko.observable().extend({ required: true, number: true});
this.currency = ko.observable().extend({ required: true});
this.requestedAmount = ko.observable();
this.requestedCurrency = ko.observable().extend({ required: true, notEqual: this.currency, message: 'please'});
this.comment = ko.observable().extend({ required: true, minLength: 3});
this.currencies = currencies;
};
ctor.errors = ko.validation.group(ctor);
ctor.prototype.activate = function (activationData) {
};
ctor.prototype.save = function () {
var valid = ctor.isValid();
console.log(valid);
if (ctor.isValid()){
ctor.errors.showAllMessages();
}
else {
var dto = ko.toJS(this);
delete dto.currencies;
changeup.createRequest(dto).then(function(request){
console.log(request, 'a');
router.navigate('dashboard');
});
}
};
ctor.prototype.cancel = function (activationData) {
};
return ctor;
});
ko validation group should be attached with this not with the function itself so your code wil be like :-
var ctor = function () {
this.amount = ko.observable().extend({ required: true, number: true});
this.currency = ko.observable().extend({ required: true});
this.requestedAmount = ko.observable();
this.requestedCurrency = ko.observable().extend({ required: true, notEqual: this.currency, message: 'please'});
this.comment = ko.observable().extend({ required: true, minLength: 3});
// this.currencies = currencies;
this.errors = ko.validation.group(this);
};
And save function will be:-
ctor.prototype.save = function () {
var valid = this.isValid();
console.log(valid);
if (!this.isValid()){ //use this
this.errors.showAllMessages();
}
else {
var dto = ko.toJS(this);
delete dto.currencies;
changeup.createRequest(dto).then(function(request){
console.log(request, 'a');
router.navigate('dashboard');
});
}
};
Fiddle Demo

Categories