Meteor mdg:validated-method without using simple schema - javascript

Well,
Simple Schema is in the middle of transitioning to a new version 2.0
And at the same time, I'm not really sure I'd like to use this in my project.
I am writing an ES6 React based Meteor application therefor I'd like to make use of The "Advanced" way to create meteor methods. However, I don't want to use aldeed:simple-schema at all.
Is there a way to put in a custom validation method here?
This doesn't work:
export const addSuggestion = new ValidatedMethod({
name: 'suggestion.add',
validate() {
return true
},
run(incommingSuggestion) {
// do things which are not relevant to this question.
}
})
It produces the following error:
Error: Returning from validate doesn't do anything; perhaps you meant to throw an error?(…)
Is there a different way to write this?
Perhaps I need to not use this validated-method, instead I should maybe write it out long-form? Edit: Edit: This works, you can write everything out long-form with all of this extra boiler plate if you want to avoid validation all together for the time being. For now this is the solution I will use until I finally decide on how I will be validating everything. I'm not sure what to do right now because Simple Schema is in transition. - Actually that doesn't work, it for some reason never returns a value and I couldn't get around that.
Anyone out there know how to get around this?
Obviously googling has not turned up any results, I've been looking at this problem now for more than three days.

You could re-implement SimpleSchema's API, but why?
SimpleSchema is a de facto standard in Meteor, like Mongoose for Node<->MongoDB. There are alternatives in the works, but I think you're pushing the bleeding edge.
If you've got work to do, use SimpleSchema.

From the Meteor Forums:
Firstly, the Meteor method should expect an object like so:
myMethod.call({
arg1: 'hello',
arg2: 25,
}, (error, result) => { /* do stuff */ });
And then your method would be defined as such: (Note, that validate() { } is empty, before I was returning true - this was the problem I was having)
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { check } from 'meteor/check';
export const myMethod = new ValidatedMethod({
name: 'myMethod',
validate() { }, // always valid
run({ arg1, arg2 }) {
// do things
}
};
When you're ready to validate the arguments, just change validate accordingly:
validate(opts) {
check(opts, {
arg1: String,
arg2: Number,
}
},
And this way we can avoid using Simple-Schema while it works out it's transition from 1.0 to 2.0 (Good luck Simple Schema!!!)
And thanks to ffxsam for providing the solution on the meteor forums!

Related

Vue - Can not use or access this.$router or vue instance in my mixin file

My src/mixins/chechauthMixin.js file is as follows:
export const checkauthMixin = {
methods: {
validateAuthentication: function(path) {
if(this.$store.getters.isAuthenticated) {
this.$router.push('/dashboard')
}
}
}
}
However, it seems that the word 'this' is undefined here. I am calling this mixin method from a component or my routes.js file. How can I access the vue instance?
If this is not possible then what is a good workaround for such a scenario?
I have a similar mixin file where I store my social authentication function and that too uses 'this' instance. When I debug and try to use the instance in the console, it states that the element is undefined. However, my authentication code is able to work properly otherwise when I am not debugging.
What is going on in the two scenarios exactly?
I think it's because you're using the old javascript call
validateAuthentication: function(path) {
if(this.$store.getters.isAuthenticated) {
this.$router.push('/dashboard')
}
}
Try using:
export const checkauthMixin = {
methods: {
validateAuthentication(path) {
if(this.$store.getters.isAuthenticated) {
this.$router.push('/dashboard')
}
}
}
}
I also use mixins and I have no problem using this.$router... but I write my mixins with the newer syntax. Hope this solves your problem
Ok so I think I figured out the issue. I'm actually using a mixin incorrectly. The mixin is supposed to be used for multiple components that share a similar functionaliy. I was trying to use a mixin as a standalone function.
What I actually wanted to use was a routeguard. So the vue-router has a function called beforeach and that's what I wanted to use but didn't know about it when I faced this issue.
If this isn't what you expect, try self:
validateAuthentication: function(path) {
var self = this;
if(self.$store.getters.isAuthenticated) {
self.$router.push('/dashboard')
}
}
Welcome to Stack Overflow. Next time, try to make your code and question as succinct as possible. "Walls of Text" (the sorta rambling paragraphs you have) make your question difficult to answer quickly, thus it will not be answered as quickly as it otherwise would have, or answered at all. Be conscientious that people on this site don't want to spend time understanding your question, so they will skip over it.
Also, be sure to add things you have tried, and what error you're getting. Good luck!

Custom Unobtrusive Validation Method Not Firing as Per Documentation

I've been attempting to implement a ASP.NET MVC custom validation method. Tutorials I've used such as codeproject explain that you add data-val-customname to the element. Then jQuery.validate.unobtrusive.js then uses the third segment of the attribute
data-val-<customname>
as the name of the rule, as shown below.
$.validator.addMethod('customname', function(value, element, param) {
//... return true or false
});
However I just can't get the customname method to fire. By playing around I have been able to get the below code to work, but according to all the sources I've read Unobtrusive validation should not work like this.
$.validator.addMethod('data-val-customname', function(value, element, param) {
//... return true or false
});
I've posted an example of both methods
jsfiddle example
Any help would be much appreciated
I've updated my question hopefully to make clearer.
I have finally found got there in the end, but still feels like too much hard work and therefore I've probably got something wrong. Initial I was scuppered by a bug in Chrome Canary 62 which refused to allow the adding of a custom method.
My next issue was having to load jQuery, jQuery.validate and jQuery.validate.unobtrusive in the markup and then isolate javascript implementation in a ES6 class. I didn't want to add my adaptors before $().ready() because of my class structure and loading of the app file independent of jQuery. So I had to force $.validator.unobtrusive.parse(document);.
Despite this I was still having issues and finally debugged the source code and found that an existing validator information that is attached to the form was not merging with the updated parsed rules, and essentially ignoring any new adaptors added.
My final work around and admit feels like I've done too much, was to destroy the initial validation information before my forced re-parse.
Here is the working jsfiddle demo
Here is some simplified code
onJQueryReady() {
let formValidator = $.data(document.querySelector('form'), "validator" );
formValidator.destroy();
$.validator.unobtrusive.adapters.add("telephone", [], function (options) {
options.rules['telephone'] = {};
options.messages['telephone'] = options.message;
});
$.validator.unobtrusive.parse(document);
$.validator.addMethod("telephone", this.handleValidateTelephoneNumber);
}

Set default value of validation

I am using Joi to validate a payload of a service in my node.js server using hapijs framework. It used to look like this (in my typescript code as well as after compiling to javascript):
payload: {
para1: Joi.number().required(),
para2: Joi.string()
}
Now I want to set default value of the two parameters. If the code is written in javascript, I can do this:
payload: {
para1: Joi.number().required().default(1),
para2: Joi.string().default("defaultstring")
}
I tested it in swagger and the default values actually became the values I set.
However, my project is written in typescript. I did the same thing and compiled typescript code. The result javascript looks like this:
payload: {
para1: Joi.number().required()["default"](1),
para2: Joi.string()["default"]("defaultstring")
}
In swagger, the default values are not applied.
Here are my questions:
why the code becomes different after compiling?
what does ["default"]("defaultstring") mean and what does it do?
how can I write typescript code to make sure it can compiled as Joi.string().default("defaultstring")
Update
According to #rsp's post, the format in question 2 is just different way to access object's property. I also get reference from here. But it doesn't explain if they have any difference. Does anyone have any idea?
Update2
Here is the difference between the two ways accessing JS property. It seems there is no negative effect using brackets way. However, in my case, the default values are not reflected on swagger. Will be doing research on it.
In JavaScript this:
required().default(1)
is the same as this:
required()["default"](1)
because you can access object properties either as:
object["propertyName"]
or:
object.propertyName
(with certain restrictions in the second case).
So it's strange that TypeScript would output the longer style if it doesn't have to, but it's also strange that the longer style doesn't work exactly the same as the shorter one.
I would try to manually change the compiled JavaScript to the shorter version and see if that helps. If it doesn't then the problem is somewhere else. My suspicion is that it will not help.
The .default() should work in TypeScript because it is defined in #types/joi - see:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/joi/index.d.ts#L272-L273
But on the other hand there is this comment:
// TODO express type of Schema in a type-parameter (.default, .valid, .example etc)
Which may suggest that .default() implementation is not ready yet - see:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/joi/index.d.ts#L6
and also there's this issue: joi.d.ts out of date, missing types
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/9332
Use should use default() like in below code:
validate: {
payload: {
para1: Joi.number().integer().min(1).max(100).default(10).required(),
para2: Joi.string().min(1).max(100).default("TEST").required(),
}
}
It still says key is required when we use Joi.boolean().required().default(true)
The below worked for me
JOI.boolean().default(false)
taxAmount: Joi.number().default(0),
totalAmount: Joi.number().default(0),
This works for me. Do not use .reqquired() keyword.
The result will be in the
const validationResult = schema.validate(data);
validationResult.value

Handling assertions in a custom helper

I've started playing around with CodeceptJs and I've got it up working quite easily. I'm currently using it with NightmareJs and all seems fine.
The specific area I'm testing is a gallery that fetches data from an interface via JSONP creating a list of images wrapped in <div>s.
A portion of the tests I'm implementing is like the following:
Feature('gallery')
Scenario('clicking on an element adds "selected" class', (I) => {
I.amOnPage('/')
I.seeElement('#gallery .col-md-3')
I.click('#gallery .col-md-3')
I.seeElement('#gallery .selected')
})
Now since the elements can be any number, it's currently silently using the first element, but in order to give it a bit more entropy I wanted to pick an element at random, something like the following
Scenario('clicking on an element adds "selected" class', (I) => {
I.amOnPage('/')
I.seeMoreThanElements('#gallery .col-md-3', 1)
I.clickOnRandomElement('#gallery .col-md-3')
I.seeElement('#gallery .selected')
})
Or even better, if I could grab the list of elements so I can decide which one to click on, like:
Scenario('clicking on an element adds "selected" class', (I) => {
I.amOnPage('/')
I.seeMoreThanElements('#gallery .col-md-3', 1)
const elements = I.grabRandomElement('#gallery .col-md-3')
const random = getRandomInt(1, elements.length)
I.click(`#gallery .col-md-3:nth-child(${random})`)
I.seeElement(`#gallery .col-md-3.selected:nth-child(${random})`)
})
The current helpers available don't allow me to perform some particular actions, so I started implementing a custom handler as described in the guide at http://codecept.io/helpers/
In my configuration I have the following:
"helpers": {
"Nightmare": {
"url": "http://localhost:3000"
},
"DOMElements": {
"require": "./__tests__/helpers/domelements_helper.js"
}
}
and domelements_helper.js currently looks like the following:
'use strict'
let assert = require('assert')
class DOMElements extends Helper {
seeMoreThanElements (locator, count) {
this.helpers['Nightmare']._locate(locator).then(function (els) {
return assert(els.length >= count, `Found more than ${count} elements`)
})
}
}
module.exports = DOMElements
This doesn't - clearly - work. This is where I'm getting a bit confused.
First of all, I'm using the default Node.js assertion library, and if there's any need I'm happy to move over to something more robust like Protractor or Chai-as-promised, but the slimmer the better.
Secondly, the documentation clearly states the following:
any helper method should return a value in order to be added to promise chain
Which doesn't really make sense... should I return a promise or should I handle the whole thing within the then() statement? As returning a basic value doesn't really do much. Even then, how do I handle failed assertions?
I've also seen a Nightmare clientscript in the code base but I have no idea if it's of any use for my case, as I've just started digging through the code base in order to understand a little bit better how to customise and extend CodeceptJs.
Any pointers are really appreciated
since nobody seems to have got this far, I'm going to add an answer as I seem to have found how this thing works by going through the codebase and understand a bit more how it works.
tl;dr: the quick solution is the following:
/* __tests__/helpers/domelements_helper.js */
const assert = require('assert')
class DOMElements extends Helper {
seeMoreThanElements (locator, count) {
return this.helpers['Nightmare']._locate(locator)
.then((elementsArray) => {
if (elementsArray.length < count) {
return assert.fail(elementsArray.length, count, `Found more than ${count} elements`)
}
})
}
}
module.exports = DOMElements
The way the whole thing works is by promises and you have to handle failure appropriately so that the whole system can fail gracefully (sorta).
In particular _locate() returns a promise and everything has to be handled asynchronously, although by design this seems to be quite awkward and it's making things particularly hard to implement, at least in the current state.

Backbone.js: How to catch typos when working with model attributes?

I'm new to JS development, and I find myself spending more than desirable attention fixing bugs caused by typos in model attributes, especially usages of model.get(). While my unit test do catch most of these, it's still annoying to fix and having to remember the names when coding. Is there something that can warn me about these typos?
One strategy that we use is to define a hash and use them for the setters and getters
var ATTRS = {
attr1: 'attr1',
attr2: 'attr2'
}
model.set (ATTRS.attr1, 'attr1_val');
model.get (ATTRS.attr1);
For some cases like since JS wont allow to use variable on the left-hand-side of a hash, you wont be able to use this. But for the most part, it helps eliminate most simple typo errors
{ ATTRS.attr: 'def_val' } // this will give an error
Hope this help
First, install the plugin _super:
https://github.com/lukasolson/Backbone-Super
Now create an abstract Model:
YourAbstractModel = Backbone.Model.extend({
get : function(attr){
if( !_.has(this.defaults, attr) ){
throw 'Invalid attribute: ' + attr;
}
return this._super(attr);
}
});
Your models should extend the abstract instead of the Backbone.Model(and you should set defaults).
I think that testing is the best approach.
Including validation/spellcheck code, that will become a part of your production application eventually, is a bad idea. If you type the name of the variable incorrectly - it should be discovered by your development-time testing, not some run-time validation.

Categories

Resources