First stages of client-side validation worked into application

pull/105/merge
Michael Jett 2012-05-16 17:22:25 -04:00
parent c45991b561
commit b06640c921
3 changed files with 97 additions and 24 deletions

View File

@ -69,6 +69,17 @@ public class ClientAPI {
return "jsonClientView"; return "jsonClientView";
} }
@RequestMapping(value="/{id}", method = RequestMethod.PUT, headers = "Accept=application/json")
public String apiUpdateClient(@PathVariable("id") String id, @RequestBody String json, Model m) {
ClientDetailsEntity client = new Gson().fromJson(json, ClientDetailsEntity.class);
client.setClientId(id);
m.addAttribute("entity", clientService.saveClient(client));
return "jsonClientView";
}
@RequestMapping(value="/{id}", method=RequestMethod.DELETE, headers="Accept=application/json") @RequestMapping(value="/{id}", method=RequestMethod.DELETE, headers="Accept=application/json")
public String apiDeleteClient(@PathVariable("id") String id, ModelAndView modelAndView) { public String apiDeleteClient(@PathVariable("id") String id, ModelAndView modelAndView) {

View File

@ -4,6 +4,51 @@
idAttribute: "clientId", idAttribute: "clientId",
initialize: function () {
this.bind('error:clientName', function(model, errs) {
$('#clientName').addClass('error');
});
this.bind('error:clientDescription', function(model, errs) {
$('#clientDescription').addClass('error');
});
this.bind('error:registeredRedirectUri', function(model, errs) {
$('#registeredRedirectUri').addClass('error');
});
},
validate:{
clientName:{
required:true,
pattern:/^[a-zA-Z ]+$/,
minlength:3,
maxlength:100
},
clientDescription:{
required:true,
pattern:/^[a-zA-Z ]+$/,
minlength:3,
maxlength:100
},
registeredRedirectUri: {
custom: 'validateURI'
}
},
validateURI: function(attributeName, attributeValue) {
var expression = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
var regex = new RegExp(expression);
return attributeValue.every(function (url) {
if (!url.match(regex)) {
return false;
}
});
},
// We can pass it default values. // We can pass it default values.
defaults:{ defaults:{
clientName:"", clientName:"",
@ -51,7 +96,7 @@
}, },
editClient:function () { editClient:function () {
alert('edit'); document.location.hash = 'client/' + this.model.id;
}, },
deleteClient:function () { deleteClient:function () {
@ -90,7 +135,7 @@
newClient:function () { newClient:function () {
this.remove(); this.remove();
document.location.hash = 'new_client'; document.location.hash = 'client/new';
}, },
render:function (eventName) { render:function (eventName) {
@ -121,25 +166,36 @@
"click .btn-primary":"saveClient" "click .btn-primary":"saveClient"
}, },
saveClient:function () { saveClient:function (event) {
event.preventDefault();
this.model.set({ this.model.set({
clientName:$('#clientName').val(), clientName:$('#clientName input').val(),
registeredRedirectUri:[$('#registeredRedirectUri').val()], registeredRedirectUri:[$('#registeredRedirectUri input').val()],
clientDescription:$('#clientDescription').val() clientDescription:$('#clientDescription textarea').val(),
allowRefresh:$('#allowRefresh').is(':checked')
}); });
if (this.model.isNew()) { if (this.model.isNew()) {
var self = this; var self = this;
app.clientList.create(this.model, { app.clientList.create(this.model, {
success:function () { success:function () {
alert('bravo!'); document.location.hash = '';
}, },
error: function () { error: function () {
alert('boo!'); //alert('boo!');
} }
}); });
} else { } else {
this.model.save(); this.model.save(this.model, {
success:function () {
document.location.hash = '';
},
error: function () {
//alert('boo!');
}
});
} }
return false; return false;
@ -147,13 +203,7 @@
render:function (eventName) { render:function (eventName) {
var action = "Edit"; $(this.el).html(this.template(this.model.toJSON()));
if (!this.model) {
action = "New";
}
$(this.el).html(this.template({action: action}));
return this; return this;
} }
}); });
@ -163,7 +213,8 @@
routes:{ routes:{
"":"list", "":"list",
"new_client":"newClient" "client/new":"newClient",
"client/:id":"editClient"
}, },
initialize:function () { initialize:function () {
@ -182,6 +233,12 @@
newClient:function() { newClient:function() {
this.clientFormView = new ClientFormView({model:new ClientModel()}); this.clientFormView = new ClientFormView({model:new ClientModel()});
$('#content').html(this.clientFormView.render().el); $('#content').html(this.clientFormView.render().el);
},
editClient:function(id) {
var client = this.clientList.get(id);
this.clientFormView = new ClientFormView({model:client});
$('#content').html(this.clientFormView.render().el);
} }
}); });

View File

@ -74,7 +74,7 @@
<script type="text/html" id="tmpl-client-form"> <script type="text/html" id="tmpl-client-form">
<h1><%=action%> Client</h1> <h1><%=(clientId == null ? 'New' : 'Edit')%> Client</h1>
<div class=""> <div class="">
@ -86,16 +86,21 @@
<div class="row-fluid"> <div class="row-fluid">
<div class="span6"> <div class="span6">
<span class="control-group" id="clientName">
<label>Client name</label> <label>Client name</label>
<input id="clientName" type="text" class="" placeholder="Type something"> <span class="help-inline">Associated help text!</span> <input value="<%=clientName%>" type="text" class="" placeholder="Type something"> <span class="help-inline">Associated help text!</span>
</span>
<span class="control-group" id="registeredRedirectUri">
<label>Redirect URL</label> <label>Redirect URL</label>
<input id="registeredRedirectUri" type="text" class="" placeholder="http://"><span class="help-inline">Associated help text!</span> <input type="text" class="" placeholder="http://"><span class="help-inline">Associated help text!</span>
</span>
</div> </div>
<div class="span6"> <div class="span6">
<span class="control-group" id="clientDescription">
<label>Description</label> <label>Description</label>
<textarea id="clientDescription" class="input-xlarge" placeholder="Type a description" <textarea class="input-xlarge" placeholder="Type a description"
rows="3"></textarea> <span class="help-inline">Associated help text!</span> rows="3"><%=clientDescription%></textarea> <span class="help-inline">Associated help text!</span>
</span>
</div> </div>
</div> </div>
@ -106,7 +111,7 @@
token after it token after it
expires.</p> expires.</p>
<label class="checkbox"> <label class="checkbox">
<input type="checkbox"> Allow refresh tokens? <input type="checkbox" id="allowRefresh" <%=(allowRefresh == true ? 'checked' : '')%>> Allow refresh tokens?
</label> </label>
<button class="btn btn-primary">Submit</button> <button class="btn btn-primary">Submit</button>
</div> </div>