How can I add custom client side validation to validation that was generated from annotations in MVC5 VB.NET - vb.net

I have added a number of annotations to do simple required field validation in a modal form. Now I need to do a somewhat convoluted check for uniqueness on a couple of the fields involved.
I want to avoid using a custom annotation to do this as the fields that require validation within the model require extra information that does not exist in the model.
I want to be able to add a new rule to the existing validation via script.
Unfortunately I can't seem to get both the new rule and the existing ones to work at the same time.
If I do the following, then only the new rule gets applied, all the existing rules (required fields etc.) disappear.
jQuery.validator.addMethod("uniqueresourceid",
function(value, element, options) {
return ResourceIDValidation(options.resourceSet, value, options.originalresourceidpropertyname);
}, "This resource ID is already inuse.");
var validator = $('#InstitutionModalForm').validate();
$('#Institution_NameResourceID').rules("add", {
uniqueresourceid: {
resourceSet: "Institutions",
resourceId: $('#NameResourceID').val(),
oldResourceId: "OriginalNameResourceID"
}
});
function ResourceIDValidation(ResourceSet, ResourceID, OldResourceIDField) {
var valid = false;
$.ajax({
type: "POST",
url: "#Url.Action("ValidateResourceID", "Admin")",
traditional: true,
contentType: 'application/json; charset=utf-8',
async: false,
data: JSON.stringify({
ResourceSet: ResourceSet,
ResourceID: ResourceID,
OldResourceID: $('#' + OldResourceIDField).val(),
}),
success: function (result) {
valid = result;
},
error: function (result) {
console.log(data);
valid = false;
}
});
return valid;
}
If I remove the 'var validator =...' line, then only the original validation (required fields etc.) fires.
I can't see any reason why this shouldn't be possible, but I can't seem to figure out how to make it work.
I'm not really clear on how the unobtrusive stuff does it's magic, but shouldn't there be a way to hook into whatever validator is being generated by the server side annotations so that I can add a new rule in the JS?

Strictly speaking, this is possible but I can see some very important reasons why you wouldn't want to do this.
Most importantly, this creates a client side validation only. This means if someone nefariously submits the form, or if they don't have JS enabled, that your server side code will not do this validation and probably break.
In addition to that, it makes your code harder to maintain as the validation is not handily visible in your code as it would be with an annotation.
While it is probably a very bad idea to do this, this is how you could make it happen. Adding this code above the "addMethod" caused it to validate as I initially intended.
$('#NameResourceID').attr("data-val", "true");
$('#NameResourceID').attr("data-val-uniqueresourceid", "Resource ID must be unique.");
$('#NameResourceID').attr("data-val-uniqueresourceid-resourceset","institutions");
$('#NameResourceID').attr("data-val-uniqueresourceid-originalresourceidpropertyname","OriginalNameResourceID");
Do this instead: Implement a custom validation annotation as Stephen Muecke suggested in the question comments. It was more work, but in the end is far better practice. This was the most helpful (to me) tutorial I could find on the subject.

Related

JSON API design - express

I want to write a JSON API.
My problem is, that sometimes I want to query for an ID, sometimes for a String.
One option would be to add a querystring, for example:
example.com/user/RandomName
example.com/user/1234556778898?id=true
and use it like:
api.get('user/:input', function(req, res) {
if(req.query.id) {
User.find({ '_id': req.params.input }, cb);
} else {
User.find({ 'name': req.params.input }, cb);
}
};
But this seems like bad practice to me, since it leads to a bunch of conditional expressions.
Are there more elegant ways?
I would suggest handling two endpoints. One for getting ALL the users and one for getting a SPECIFC user by ID.
example.com/users
example.com/users/:id
The second endpoint can be used to find a specific user by id.
The first endpoint can be used to find all users, but filters can be applied to this endpoint.
For example: example.com/users?name=RandomName
By doing this, you can very easily create a query in your Node service based on the parameters that are in the URL.
api.get('/users', function(req, res) {
// generate the query object based on URL parameters
var queryObject = {};
for (var key in req.query) {
queryObject[key] = req.query[key];
}
// find the users with the filter applied.
User.find(queryObject, cb);
};
By constructing your endpoints this way, you are following a RESTful API standard which will make it very easy for others to understand your code and your API. In addition, you are constructing an adaptable API as you can now filter your users by any field by adding the field as a parameter to the URL.
See this response for more information on when to use path parameters vs URL parameters.

Durandal KO binding when data is fetched in activate

A parameter governs what data is to be displayed. The parameter is retrieved from activationData in the activate method of the view model and used in a call to a Web Api method. Data is returned, and added to the view model like this
define(['durandal/app', 'knockout', 'moment'],
function (app, config, ko, moment) {
var vm = {
app: app
};
vm.activate = function (activationData) {
vm.ChecklistInstanceId = activationData.ChecklistInstanceId;
$.ajax({
url: "api/ChecklistInstance/" + vm.ChecklistInstanceId,
headers: { Authorization: "Session " + app.SessionToken() }
}).done(function (data) {
$.extend(vm, ko.mapping.fromJS(data));
});
};
return vm;
});
Inspecting the viewmodel immediately after it is extended reveals that it is decorated with observables exactly as expected. For example, vm.Caption() exists and returns the string I expect, and vm.Section() is an appropriately populated observable array, and so on down a fairly elaborate object graph.
The problem is the binding phase has already occurred, and at that time the view model lacks all the observables to which I'm trying to bind.
Two possible strategies suggest themselves:
obtain the parameter earlier
re-bind
I don't know how to do either of those things. Can anyone tell me how to re-organise my code to allow binding to parametrically fetched data?
A third possibility occurred to me:
define(['durandal/app', 'knockout', 'moment'],
function (app, config, ko, moment) {
var vm = {
app: app,
Caption: ko.observable(),
Section: ko.observableArray()
};
vm.activate = function (activationData) {
vm.ChecklistInstanceId = activationData.ChecklistInstanceId;
$.ajax({
url: "api/ChecklistInstance/" + vm.ChecklistInstanceId,
headers: { Authorization: "Session " + app.SessionToken() }
}).done(function (data) {
var foo = ko.mapping.fromJS(data);
vm.Caption(foo.Caption());
vm.Section(foo.Section());
});
};
return vm;
});
This works because all the observables exist in the binding phase. This might seem surprising given that I describe only the root of a potentially deep object graph, but the fact that the observable array is empty causes the binding phase to exit without a hitch.
Later in the activate handler, values are added to the observable array after ko.mapping has its way with the data, and binding succeeds.
I have a sense of dèja vu from this: it is eerily reminiscent of problems solved using forward declarations in TurboPascal back in the eighties. La plus ça change...
In order to work on a fully-constructed view, you will need to move your logic to either the attached handler or the compositionComplete handler. As you said, at the activate stage, the DOM isn't yet fully constructed. You can read about these lifecycle callbacks here.
Typically, what we do is pass the activationData in through the activate handler, store the activationData locally (if your viewModel is instance-based, then on a property in the constructor), and then reference that activationData in the attached or the compositionComplete handler.
You can fetch the data in the activate handler, and then store the data locally. But that's all you should do there. Reserve view-related logic for later in the cycle. In this case, you may need to return a promise from activate, and then resolve upon receiving your data. You can read about it here.
UPDATE
Take a look at this post, and the conversation there.

I am getting a $save() not a function in Angular

I am trying to build a relatively simple web application following tutorials from the book ProAngular. The book examples work fine, but when I try and build my own app, I am getting stuck on a strange error. Here is part of my code:
$scope.dispositionsResource = $resource(dispositionUrl + ":id", { id: "#id" },
{ create: {method: "POST"}, save: {method: "PUT"}, delete: {method: "DELETE"}
});
. . .
$scope.updateDisposition = function (disposition) {
alert("DISPOSITION: "+disposition.name);
disposition.$save();
}
The Create and Delete functions work fine. The updateDisposition method is being called form an HTML form and the correct disposition value is being passed (based on the Alert). But the error I am getting is:
"Error: disposition.$save is not a function"
None of my example code separately defines a save function, the function should be part of the restful service ($resource). Shouldn't it?
Any pointers in the right direction would be greatly appreciated.
Ted
I did end up getting this working. Not totally sure why, but I renamed the Save function to 'Update' and associated it with the PUT functionality.
$scope.dispositionsResource = $resource(dispositionUrl+":id", { id: "#id" },
{ 'create': {method: "POST"}, 'update': {method: "PUT"}
});
$scope.updateDisposition = function (disposition) {
$scope.dispositionsResource.update(disposition);
$scope.editedDisposition = null;
}
calling update rather than save worked. Something seemed to be interfering with using the term 'save'. Like I said, not sure what . . . yet. One of those head-scratchers for me. Thanks to those who tried to assist!
I am learning angular myself, but the first problem I can see with your code is that it doesn't look like you are defining $resource correctly ( fair warning, Angular has a ton of caveats and you may simply be delving into one I am not aware of).
I believe a more straight forward way of doing what you are trying to do is first creating an angular factory for the $resource, like so:
angular.module('yourModuleName')
.factory('disposition', function($resource) {
return $resource('/whatever/url/youwant/:id', {
id: '#id'
})
});
And then from there, declare the factory as a dependency for your controller:
angular.module('yourModuleName')
.controller('yourControllerName', function($scope, disposition) {
$scope.submitForm = function($scope)
disposition.save($scope.nameOfYourModel);
});
One thing to keep in mind is that $resource has all of the methods that you declared by default. From the docs at https://docs.angularjs.org/api/ngResource/service/$resource these are what are available out of the box:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };
Personally, I prefer to use the $http service myself. Yes, it is quite a bit more verbose than using $resource but I feel that it is much easier to understand $http when starting with angular than the $resource service. To save yourself from a world of headaches in the future, I highly recommend becoming familiar with the concept of promises in Angular as many of its services make use of them.
Good luck.

Getting results from api

I am trying to do a domain availability search using an API from free domain API.
After i create an account, it shows:
**Make a REST request using this URL:**
http://freedomainapi.com/?key=11223344&domain=freedomainapi.com
And looking in the documentation page, it has only:
Request http://freedomainapi.com?key=YOUR_API_KEY&domain=DOMAIN_NAME
Result:
{
"status": "success",
"domain": "freedomainapi.com",
"available": false
}
I am very new to APIs...
What I need is to show a domain search box, and when the user enters, it should return with result.
It claims to show domain suggestions as well. I hope it will also work.
Using jquery and a jsonp proxy
http://jsfiddle.net/mp8pukbm/1/
$.ajax({
type: 'GET',
url: "https://jsonp.nodejitsu.com/?callback=?",
data: {url: 'http://freedomainapi.com?key=14ejhzc5h9&domain=freedomainapi.com'},
dataType: "jsonp",
success: myfn
});
function myfn(data) {
console.log(data);
}
you have to use the proxy because cross domain json is not permitted
EDIT:
i made an update to show the result in a div (stringified)
http://jsfiddle.net/mp8pukbm/2/
EDIT #2: i created a test key on that site, you have to use your own
EDIT #3: and there's your combo: http://jsfiddle.net/mp8pukbm/4/
Assuming that you will use java script for showing the search box, you can use AJAX feature of java script (or jQuery or Dojo) ... All you need to do is a "GET" request that like you can pasted and you will get the result back on the response object. To try out the API you can use "Postman" application in Chrome. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
In the response object of the AJAX call you will get a JSON object which you can parse and display the result.
Normally when we use REST we need to differentiate one REST call from another.
Assuming this url
http://freedomainapi.com/checkAvailability?key=YOUR_API_KEY&domain=DOMAIN_NAME
In Application layer we need to write an interface
#GET
#Path("/checkAvailability")
#Produces({MediaType.APPLICATION_JSON})
public ReturnObject getDomainAvailability(#QueryParam("key") String key,
#QueryParam("domain") String doaminName );
Once interface is done you need to write your implementation class.
This class will intract with business layer and perform search task and based on
result collected will create ReturnObject.
ReturnObject => will contain status, domain and availability
On screen
$.ajax({
type: "GET",
url: 'root/checkAvailability',
success: function(jsonData)
{
// read json and perform operation
}
,
error: function (error)
{
// handle error
}
});
If you are using JAVA as backend then you can use gson to parse the result, which is a json. After parsing you can read the values from result and display accordingly :)
Any API is a way to extend a given software. (Might be a website or an application)
In both ways there is a certain way to communicate with the software. In your example freedomainapi.com allows you to fetch if given domain is avaiable. There is no such thing as a suggestion tho, atleast i cannot find any suggestions at all.
Given output is a message format know as JSON. It can be easily interpreted by many major Languages such as Java, Javascript and PHP.
Given String might be easily interpreted as a Map consisting of a status (String), a domain (string) and avaiable (boolean)
A domain availability search could not be easier, assuming K is your key, D is your search input (Domain):
Download http://freedomainapi.com/checkAvailability?key=K&domain=D as input
Parse JSON from input as json
return json["status"] == "success" and json["avaiable"]
Depending on your language you might need to use methods to access properties of json, but that does not influence the basic usage of this api.
on user enters, it calls click_button function and I am assuming your result displaying div id is "main_container" you can give domain suggestions by passing related DOMAIN_NAME s as arguments to click_button function
function click_button(DOMAIN_NAME){
$.ajax({
url : 'http://freedomainapi.com?key=YOUR_API_KEY&domain=DOMAIN_NAME',
type: 'GET',
crossDomain: true,
contentType: "application/json; charset=utf-8",
success: function(data) {
data=JSON.parse(data);
if(data['available']){
$('#main_container').html($('#main_container').html()+'<br>'+DOMAIN_NAME+': Available');
else{
$('#main_container').html($('#main_container').html($('#main_container').html()+'<br>'+DOMAIN_NAME+': Not Available');
}//success
});//ajax
}
hope it helpful !

Backbone.js using non-restful actions on a restful model

I have a regular restful model that I do get, create, delete and update. On top of that, I'd like to call special actions on that model, like change_password.
The regular RESTful routes are traditional Rails 3 routes:
fetch => GET /api/models/:id
save => PUT /api/models/:id
create => POST /api/models
destroy => DELETE /api/models/:id
But, on top of those, I have special operations:
changePassword => GET /api/models/:id/change_password
activate => GET /api/models/:id/activate
And so on.
What do I need to setup on the model, so it recognizes those new actions, and how to wrap the calls into model methods?
It's fairly simple to add new methods to a Model - just specify the new methods in .extend(). You have to code some of this yourself, but you can take advantage of existing machinery like Backbone.sync (mostly just a wrapper around $.ajax()) and the Model's existing url property:
var MyModel = Backbone.Model.extend({
activate: function(opts) {
var model = this,
url = model.url() + '/activate',
// note that these are just $.ajax() options
options = {
url: url,
type: 'POST' // see my note below
};
// add any additional options, e.g. a "success" callback or data
_.extend(options, opts);
return (this.sync || Backbone.sync).call(this, null, this, options);
},
// etc
});
Just as a comment, from a REST perspective, your changePassword and activate operations should not be GET methods - all GET methods should be idempotent. This is not just RESTifarianism, it's a Good Idea - you could end up caching these URLs (so nothing happens) or hitting them multiple times by accident (usually requiring user confirmation with a POST request). Make these POST calls if you can.
I would advise that if possible add a Password model/controller where you can call save on to change the password. This follows the REST standards and is built in functionality of Backbone.js
If that's not an option, the following is a CoffeeScript example, add this to your model:
activate: ->
unless user.get('active')
(#sync || Backbone.sync).call #, 'activate', #,
url: "#{#url()}/users/#{message.get('id')}/activate"
data: {}
complete: =>
user.set(active: true)
#set(active: true)