Within a CREATE operation using the model validation and the "isUnique" rule, I check whether a specific value already exists in the database.
My application is a dictionary. In some cases it IS necessary to skip that validation and to allow the application to create more than one entry for one and the same word. Therefore I need a way to manipulate the validation as follows:
The validation returns an error message, as usual. In addition, there should be displayed a checkbox with a label that says something like "I confirm I want create another entry for this word" If I check the checkbox and submit the form again, then the validation should return true and the word will be stored. If the checkbox remains unchecked, the validation will continue to return false.
I thought of something like this (it's only pseudo code to illustrate what I mean. I KNOW that this is not working PHP code)
function afterValidate() {
if ($this->validationErrors contains the observed field) {
if ($this->data does NOT contain the extra checkbox) {
extend $this->data with an extra checkbox;
}
else {
if (extra checkbox is checked) {
force validation to return true;
save record;
}
}
}
}
Unfortunately, I can't get it working in my model!
My first obstacle is on the second IF construct: How do I extend the data object within the model?
I can push stuff into it (my desired checkbox) and even see it, when I debug using the pr() command. But neither the Controller nor the View sees it: when I output the data object in the Controller or in the View it still contains the standard form fields but not the checkbox…?
I presume I could move the code to the Controller and get it working there, but I think it rather has to happen in the model since there is the afterValidate callback for post-processing data.
Thanks for hints!
Related
I'm using the Angular framework with Angular Material controls in my recent application. I'm looking for a good solution for the following problem:
A form form with an input field named nickname is shown to the user. After the user has chosen a nickname and submitted the form, the server checks whether the nickname has already been taken. In that case, it returns an error to the Angular client.
To show an appropriate error to the user, the code then calls form.nickname.$setValidity('nicknameTaken', true). The new ngMessages module is used to display the error to the user. Further form.$isInvalid is used to disable the form controls to prevent the user from resubmitting the invalid nickname.
My problem is now the following: I'd like to have the error nicknameTaken automatically being removed as soon as the user begins to edit the form fields again. What is a good way to do this? Is there a predefined route to go when it comes to server-side validation errors of this kind? (Note that I am not asking for asynchronous validation because I only want to contact my server when the form is actually being submitted.)
I would write a normal validator directive instead. Something like
<input blacklist="takenNickNames" .../>
This directive would simply add a validator to the input, and this validator would make the input invalid if the model value is contained inside the given takenNickNames array (and valid if it's not present).
The takenNickNames array would be empty initially. When the form is submitted and the error comes back, the controller would add the invalid nick name to the array.
So, every time the user would enter something, the validator would be triggered, and would set the field valid or not, based on the taken nicknames stored in the array.
Here is a working example.
Here's what I am trying to accomplish:
A user fills out a form, saves a record. At some later date they wish to "clone" this record, but may want to make a few tweaks. This "clone" functionality should direct them to a form that is pre-filled with the previous record's data so that they can review it, edit as needed, and submit it as a new record.
What I'm trying:
I've modified my add() function to accept a parameters:
function add($cloneid = NULL)
Then created a Clone link that sends them to siteurl/model/add/id_to_clone
Then, I get the data from that model:
$clone_source = $this->Model->findById($cloneid);
$this->data['Model']['field1'] = $clone_source['Model']['field1'];
and so on. Based on Google searching and other posts, this should work. But what actually happens is that upon clicking the 'Clone' link, the user is directed and the form submits itself immediately (failing to save the record, since it fails validation) and the user never actually sees the form.
What am I doing wrong? (Also I should note, there are relational models present, but I don't think this should be the cause of any problems...I hope).
Forms are pre-populated using the $this->request->data array.
In order for your form to be populated you will need to set some data to the request.
So you'll be better off with the following.
$this->request->data = $this->Model->findById($id);
Is there a way to suppress model validation in Backbone.js when a new model is first created?
In my app, I have a collection with an arbitrary number of models, which are represented as list items. The user can click a button on each item, which inserts a new empty item beneath the current item. The empty item is failing validation, obviously, because I don't want an empty item being saved later.
There's no way for me to know what sensible defaults might be when I'm creating the new item, so prepopulating the new model with valid data doesn't seem like an option.
Any suggestions?
Update: While working on a tangentially related problem, I realized that I was using Backbone.js version 0.9.0. When this version was released, other people had the same problem I was having, and they complained in this issue on GitHub.
Jeremy modified validation in 0.9.1 to fix this. Adding a (temporarily) empty model to a collection is a valid real-world usecase. You could handle the new, empty model in the view, but if you're managing a list of items like I am, that forces you to have a collection of item views (including the empty one) in addition to your collection of must-be-valid models. That's a really clunky workaround for an otherwise straightforward scenario. Glad this got fixed.
You're not supposed to add invalid models :)
Digging a bit in Backbone source code (0.9.1 at least) showed that the mechanism can be circumvented by passing options to your add method:
var Mod=Backbone.Model.extend({
validate: function(attrs,opts) {
if (opts.init) return;
return "invalid";
}
});
var Col=Backbone.Collection.extend({
model:Mod
});
var c=new Col();
c.add({},{init:true});
console.log(c.length);
A Fiddle: http://jsfiddle.net/jZeYB/
Warning : it may break things down the line.
Do you need to add the model to the collection right away? I presume that validation fails because you add it to the collection immediately.
Instead, when the button is pressed you could just create the view and blank model. When the model validates you add it to the collection. You would need a submit button/mechanism on the new row to add it to the collection (which invokes validation automatically).
I have a form in CakePHP to save information to multiple models.
My first model is "World", I have no problem for these fields the validation is correct and it's saved correctly to the database.
The second model is "Country", I use something like this:
echo $this->Form->input('Country.0.name');
This is correctly saved to the database, but there is no validation (like stairs for required fields) and no automagic (autodetection of the content type).
The third model is "Region", I use the same code as for the second one but there is no validation, no automagic and no saving...
Can someone help ?
Thank you,
Sébastien
Without seeing the rest of your code, I am guessing that you are trying to save multiple countries at the same time. The model expects the data to come in a specific format:
$this->data['Model']['field'];
What you are passing is:
$this->data['Model'][0]['field'];
The model cannot interpret it. The way to resolve this is build a foreach when you collect the data and send each request independently.
foreach($country as $field) {
$data['Country']['field'] = $field;
// add other fields that are required
if($this->Country->validates($data)) {
$this->Country->create();
$this->Country->save($data);
} else {
// error handling
}
}
Good luck and happy coding!
I have a WinForm and few properties that are set on it.
for example : Name,Address are accepted on the Form.
(many more properties in actual example)
The current implementation is somewhat similar to
frmName frmView = new frmName (); //frmName is WINFORM
frmView.Name= "ABC"; //any valid string or read this from file
frmView.Address="SomeAddress"; //any valid address or read this from file
if (frmView.ShowDialog() == DialogResult.OK)
{
//OK CLICK PROCESS and
// get new values edited by user
string name = frmView .Name;
string address = frmView.Address;
doProcessing(name,address);
}
else{
//Ignore cancel click..
}
how do i convert this to a MVP based Winform application.
Also need to refactor the processing done on ShowDialog() to the Presenter/Model
(dunno exactly where to do it)?
Also need to avoid writing code on the form itself.(Passive view)
Thanks All.
I'm still experimenting with different MVP approaches myself, but the way I'm currently doing it is like so:
frmName frmView = new frmName();
if (frmView.ShowDialog() == DialogResult.OK) {
presenter.RequestProcessing(frmView.Name, frmView.Address);
} else {
//Ignore cancel click..
}
You say you want to avoid writing any code on the form itself, but this doesn't make sense to me. In Passive View, you pass on all application-specific requests to the controller or presenter.
In this example, the view handles view-related logic. Opening the dialog box isn't a user action that anything else (such as the presenter) needs to be informed about. Just like opening a context menu, a dialog box is part of how this particular view chooses to offer those application-specific requests to the user. Until the user actually goes through with it and submits the request, the presenter doesn't need to know anything.
In some circumstances where I've needed to be able to handle errors within the dialog box itself, I've passed the IPresenter object into the dialog box's constructor. It can then make the appropriate presenter request itself when the "OK" button is clicked, for example, and can show a message box instead of closing in case of an error.
There are a lot of variations on MVP, but I hope this helps. Good luck with setting it up.