I'm looking for an option or a way to bind an event, which invokes a method from an Entry-Widget.
Like the command option for button-widgets: command { method } or
like binding an event for combobox-widgets:
$combobox.bind("<ComboboxSelected>") { method }
Now I'm looking for something similar for Entry-Widgets. I want to invoke a method every time an entry (value) has been edited. That's my initial situation:
$foo = TkVariable.new
$entry = Tk::Tile::Entry.new(parent) {
validate 'key'; validatecommand method; textvariable $foo
}
validatecommand works only at the first time.
If you change the content of the widget during the validation callback and still want to have a validation callback applied in the future, you must re-apply the validation callback. This is documented (for the core Tk version of this, see the end of the validation section of the entry docs) but pretty obscure, to be fair.
Use Tk::after.idle to schedule some code to reapply the validation callback inside the validation callback.
Related
I have some event Samevent.
For example my event have two listener;
$result = event(new Samevent());
I must be check result;
1 case
FirstListener return false;
SecondListener return false;
dd($result) = [];
2 case
FirstListener return false;
SecondListener return true;
dd($result) = [];
3 case
FirstListener return true;
SecondListener return false;
dd($result) = [true];
4 case
FirstListener return true;
SecondListener return true;
dd($result) = [true, true];
Why happens this?? How can I fix it
The reason everyone here is saying this is a mis-use of Events and Listeners is because their whole purpose is to be fired off asynchronously. When you trigger a listener, the content of that listener can't be guaranteed to finish executing before the thing that triggered it moves on. For that reason, they're not set up to offer a return.
Some more details about why you feel the desired logic must be from a Listener would be helpful, we may be able to guide you to a better pattern. For now though, I'd say you have a few options. In order of preference:
Abstract the content of your Listener's handle() method into a brand new service class. The class that you currently feel needs to access this Listener, and the Listener itself, can then reference this Service class independently of each other.
Don't fire your Listener class off an Event. Instead, instantiate it as a normal class, and then call it's handle() method directly to get your desired response.
Set config(['app.queue_driver' => 'sync']) to ensure listeners are fired off synchronously. (Make sure to change it back in a subsequent line after you trigger the listener that's intended to be synchronous, or else this could have unintended consequences for the rest of your App.) Then change your Listener so that whatever handle() does get stored in a property accessible by a new Getter method therein. This options is not advisable though. It can be done, but is so sloppy I hesitate to even suggest it. But I'm no stranger to making my code do weird things for the sake of unit-tests, so I'm not going to presume to know your circumstances.
If you need to get the result from a function, you shouldn't use the Event system to trigger that function.
You should refactor your code in one of two ways:
1) Stop using an event, and use something like a non-queued job/interaction.
$interaction = new Interaction;
$result = $interaction->handle($vars);
dd($result);
2) Pass all the variables that are required into the event, so that your listener can do any post-event processing within the listener itself.
I have an observer module that I have written for Magento. It simply monitors an event called mgd_order_prep which is triggered by a custom dispatcher like this:
Mage::dispatchEvent("mgd_order_prep", array('orderdata' => $order));
$order is simply a magento sales/order object.
My event fires and my function in the proper class executes:
function updateOrderPrepPDF($observer)
{
Mage::log("Update Order Prep",null,'orderprep.log');
Mage::log($observer->getOrderdata(),null,'orderprep.log');
}
I see what I should after the first log event, but I dont see ANYTHING for when I try to output the order data (it outputs blank - or null).
How do I get the data I pass in at the dispatch event out at the execution point?
You can directly get Data using getData() method :
function updateOrderPrepPDF($observer)
{
Mage::log(print_r($observer->getData(),true),null,'orderprep.log');
}
Check this log inside var/log directory.
Try this code and let me know if you still have any query.
We use the following general pattern with Grails controllers and command objects
SomeController {
def someAction() {
SomeCommandObject co = SomeCommandObject.valueOf(params)
if(!co.validate()) {
// return bad request
}
someService.doWork(co)
// return ok
}
SomeService {
def doWork(SomeCommandObject co) {
notTrue(!co.hasErrors(), 'cant have errors') // Commons validation
// do actual work
}
}
Apparently, if co.validate() has not been called, .hasErrors() will always return false. Is there a better way to enforce that .validate() has been called before a command object is passed between application layers? We don't want to pass around invalid command objects but we don't want to force every new method to re-validate the command object either.
Note: We aren't using the default controller/command object creation pattern because we need to do some custom parameter map checking, we use a static valueOf method instead to create the command object. Answers that change that practice are also welcome.
EDIT: A little more info on why we aren't using the 'default' controller/command object creation. Specifically why we aren't doing ..
def someAction(SomeCommandObject co) {
}
We have a requirement to disallow random query parameters, eg. endpoint/object?color=blue. To do that we need access to the parameter map in the command object to verify that it doesn't contain any 'unexpected' parameter keys. As I understand it, the default way would just create a member on the CO named color, and I don't see how to prevent arbitrary members using even custom validators. I'd happily entertain suggestions for doing so, thereby allowing us to use this default means.
Yes; what you can do is pass the command object as a parameter to the controller, and then the command will always be validated automatically.
Also, what you can do, is to make a filter or similar, so that you don't have to check for the hasErrors() each time, but handle all the cases in the same way (for example, by throwing an error, or returning with a specific response).
In an application we created, we had something like:
withValidCommand(cmd) {
// do work
}
Which worked pretty well. But maybe you can come up something even more elegant.
You should be doing this:
def someAction(SomeCommandObject co) {
if (!co.hasErrors()) {
someService.doWork(co)
}
}
By passing SomeCommandObject in as the argument grails will automatically populate it from params and validate. No need to do it manually.
I have a custom event that I want to fire using jQuery's trigger method:
$(wizard).trigger('validatingStepValues');
Then in the wizard's current step code, I subscribe to this event as follow:
$(wizard).bind('validatingStepValues', function (){
// Validating step's form data here; returning false on invalid state.
});
Then in my wizard, again I want to be able to stop user from going to the next step, if a false value is returned from validation process? I'd like to have something like:
$(wizard).trigger('validatingStepValues', validReturnCallback, invalidReturnCallback)
Have you considered using something like:
function wizardValidator(successCallback, failureCallback) {
return function() {
// Validating step's form data here;
if (wasValid && successCallback) {
successCallback();
}
else if (! wasValid && failureCallback) {
failureCallback();
}
return wasValid;
};
}
$(wizard).bind('validatingStepValues', wizardValidator(validReturnCallback, invalidReturnCallback));
This requires that you know the callbacks that you want to use at the time you bind the event listener. If you want to be able to use different callback functions at different times, you could define additional event types, like:
$(wizard).bind('validatingStep2Values', wizardValidator(validStep2ReturnCallback, invalidStep2ReturnCallback));
$(wizard).bind('validatingStep3Values', wizardValidator(validStep3ReturnCallback, invalidStep3ReturnCallback));
Alternately, events that you create by calling trigger() propagate up the DOM hierarchy. Returning false an event handler cancels this propagation. So you could bind your desired success callback function as an event listener on your wizard's parent node. That won't do anything to allow your failure callback to be executed, however.
I have a situation where I'm editing a snippet of data within a larger context. The user submits this data to a specialized action for handling and redirects back to the parent page. Because it's a redirection, validation errors aren't getting automagically set, so I'm trying to work around that.
In the event of an error, I'm writing a validation_errors key to the session with a value of $model->validationErrors. In the form, though, I'd like to tell Cake to set each error so I can leverage my existing styles and not have to make a lot of changes to my $this->Form->input() methods.
Is something like this possible? Essentially, I'm looking to manually achieve the same result you'd get if a regular form was submitted and allowed to drop through with validation errors. I was hoping I could loop over each validation error and set the field error, but that's not making any change at all.
Thanks.
This can be achieved in the controller by
$this->Model->invalidate('fieldName', __('ErrorMessage', true));
If the values are available, you can also call
$this->Model->validates();
to validate all values with the validators defined in the model.
Save the data to the session and revalidate it.
function childAction() {
if(isset($this->data)) {
$this->Session->delete('invalid_data');
if($this->Test->save($this->data)) {
// ...
} else {
$this->Session->write('invalid_data', $this->data);
}
$this->redirect(array('action'=>'parentAction'));
}
}
function parentAction() {
if($this->Session->check('invalid_data')) {
// This will cause $this->Test->validationErrors to be populated
// Assuming your parent page has the form set up properly, the
// errors will be automagically filled. ie: $form->input('Test.field1')
$this->Test->set($this->Session->read('invalid_data'));
$this->Test->validates();
}
}
If you want to do the same with CakePHP 3, use the method "errors".