Trigger change on value of form field change - phoenix-framework

I have a liveview form and a text input:
<%= search_input :filter, :search, id: "filter_search_field", class: "input", placeholder: "Search", value: #search_field, "phx-debounce": "300"%>
Now there is a moment when I want to clear this field programatically, I do this by changing the assign:
{:noreply, assign(socket, :search_field, "")}
The problem with this is that the phx-change event assigned to the form is not triggered.
I also tried to create a JS hook and change the value of the field from the hook, however that does not create event either.

As it turns out, changing value is not enough to trigger change, a change event should be emitted, on user input that event is triggered. More information can be found here.
There are few approaches to handling this now:
Creating a hook for input and emit change event on input change. The downside of this is that you will get duplicate events on user input.
Adding the hook to the button (in my case I have a reset button). From here you can trigger the event manually.
What I ended up doing is a little different. Hooks have a method called pushEvent, so I used that to trigger the handle_event:
Hooks.TestHook = {
updated(){
this.pushEvent("filter", {_target: ["filter", "search"], filter: {search: ""}});
}
}
The variant with creating a custom change event can be found here.

Related

Can comparing content in CKEDITOR on a change event impact performance?

From https://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR.editor-event-change
If it is important not to get the change event fired too often, you should compare the previous and the current editor content inside the event listener. It is not recommended to do that on every change event.
I don't understand the above ... is there possibly a typo?
Is it trying to say that a call such as checkDirty on every change event could result in poor performance?
Would using an interval timer be a good approach to limit the number of checkDirty calls made.
For example, do not call checkDirty unless at least 1 second had passed from its last invocation?
The use case I have is enabling or disabling a save button based on the editor content differing from its last saved state.
I deal with this situation by always having the save button enabled and:
1) Every time a user presses the save button, I alert him that the contents have been saved and I clear the dirty flag:
CKEDITOR.instances.editor1.resetDirty();
2) I register an onbeforeunload event handler to alert him if he tries to exit the webpage having unsaved data:
window.onbeforeunload = function() {
if (CKEDITOR.instances.editor1.checkDirty()) {
return 'You will lose the changes made in the editor if you don't save them.';
}
}

Knockout - Disabling the default behavior of updating model when using binding value with form element

Knockout has the default behavior of updating the associated model if you change your focus (e.g. by clicking outside the input control) after editing the value inside an input control, populated by a binding of type Value.
Here is the link to the official documentation page explanation, section Parameters:
http://knockoutjs.com/documentation/value-binding.html
Do you know a way to disable this default behavior ?
The reason behind this : Im using Models that can tell if their last update requires persistent backup by comparing the previous value to the new one.
I would like to listen to the key up event on my form inputs but if I do that, knockout triggers twice event (the default one + the key up) to update the Model and the second one is basically telling my Model to replace the value by the same value because it is already updated, which it translates to "there is no need to do persistent backup since the value didnt change".
I would gladly appreciate any help or suggestion, since Im stuck and can't find a way around :)
EDIT
Couldnt reproduce the error with bare backbone code. It seems as "super cool" said that valueUpdate should override the default Blur event that triggers when you use form controls with binding Value.
It may be a bug introduced by the library Knockback that I use to create the ViewModel.
Despite all this, just replacing the binding Value by the binding textInput did the trick. Thank you all.
Don't listen to the event, subscribe to updates, which won't fire unless the value is changed. Using the textInput binding will register every change to the value, even those done using menu items like cut and paste, when they happen.
Equivalently, you can use the value binding along with valueUpdate: 'input'
vm = {
myvar: ko.observable(),
updates: ko.observableArray()
};
vm.myvar.subscribe(function(newValue) {
vm.updates.push(newValue);
});
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="textInput: myvar" />
<div data-bind="foreach: updates">
<div data-bind="text: $data"></div>
</div>

The getButton method is returning undefined

attempting to call $(this).fineUploader("getButton", id); in the submit event handler and getting undefined as a result.
I assume the buttons are being tracked since access to the button is available within the validate and upload events. However, I really would like to know which button was clicked during the submit event so I can set parameters for the specific file upload. The validate event has no file id present to associate specific parameters
In Response to Comments, additional information:
Fineuploader Version 4.1.1
I have tried the scenario in many configurations and getButton method call never works in the submit handler
myfineuploader.on('submit', function(event, id, name) {
var button = $(this).fineUploader('getButton', id);
console.log(button); // Button always shows undefined here
}
The buttons are defined as spans outside of the template, setup like this in the config:
button: $("#button1"),
extraButtons: [
{
element: $("#button2")
}
]
The button is not associated with the file until after the submit event callback has completed. This was done to ensure that mappings were created only for files that passed all possible validation steps, since it is possible to reject a file in your "submit" handler as well. After some thought, it may be best to create this button to file mapping as soon as we have created an ID for this file internally. I've created an item in our issue tracker to deal with this.
If you move your logic into a "submitted" event handler instead, you should be good to go.

jQuery 'on' not registering in dynamically generated modal popup

I was under the impression that jQuery's on event handler was meant to be able to 'listen' for dynamically created elements AND that it was supposed to replace the behavior of live. However, what I have experienced is that using on is not capturing the click event whereas using live is succeeding!
The tricky aspect of my situation is that I am not only dynamically creating content but I'm doing it via an AJAX .get() call, and inserting the resultant HTML into a modal .dialog() jQueryUI popup.
Here is a simplified version of what I was trying to accomplish (wrapped in $(document).ready(...) ):
$.get("getUserDataAjax.php", queryString, function(formToDisplay) {
$("#dialog").dialog({
autoOpen: true,
modal: true,
buttons...
}).html(formToDisplay);
});
$(".classThatExistsInFormToDisplay").on("click", function() {
alert("This doesn't get called");
});
From the documentation for on I found this which which was how I was approaching writing my on event:
$("p").on("click", function(){
alert( $(this).text() );
});
However, for some reason, live will work as I expect -- whereas on is failing me.
This isn't a question for "how can I make it work" because I have found that on will succeed (capture clicks) if I declare it inside the function(formToDisplay) callback.
My question is: what is wrong with on that it isn't finding my dynamically created elements within a modal popup? My jQuery instance is jquery-1.7.2. jQueryUI is 1.8.21.
Here are two jsFiddles that approximate the issue. Click the word "Test" in both instances to see the different behavior. The only difference in code is replacing on for live.
Where the click is captured by live.
Where the click is NOT captured by on (click 'Test - click me' to see nothing happen).
I realize I may just be using on inappropriately or asking it to do something that was not intended but I want to know why it is not working (but if you have something terribly clever, feel free to share). Thanks for your wisdom!
Update / Answer / Solution:
According to user 'undefined', the difference is that on is not delegated all the way from the top of the document object whereas live does/is.
As Claudio mentions, there are portions of the on documentation that reference dynamically created elements and that what you include in the $("") part of the query needs to exist at runtime.
Here is my new solution: Capture click events on my modal dialog, which, although it does not have any content when the event is created at runtime, will be able to find my content and element with special class that gets generated later.
$("#dialog").on("click", ".classThatExistsInFormToDisplay", function() {
... //(success! Event captured)
});
Thanks so much!
live delegates the event from document object, but on doesn't, if you want to delegate the event using on method, you should delegate the event from one of static parents of the element or document object:
$(document).on("click", ".clickHandle", function() {
alert("Content clicked");
});
The problem is that the element to which you attach the event has to exist.
You have to use on like this to capture clicks on p tags created dynamically
$("#existingContainerId").on("click", "p", function(){
alert( $(this).text() );
});
if you have no relevant existing container to use, you could use $("body") or $(document)
If selector is omitted or is null, the event handler is referred to as direct or directly-bound. The handler is called every time an event occurs on the selected elements, whether it occurs directly on the element or bubbles from a descendant (inner) element.
When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler, as described next
Take a look to section Direct and delegated events here for more details

How can I validate my Firefox extension's preferences?

What is a generally accepted way to validate preference values in a Firefox extension, specifically when using the prefwindow mechanism in XUL?
I am introducing some new preferences in one of my extensions that I would like to validate before the preferences window is closed. If there's an error, the user should be allowed to correct the issue, and then proceed. I see that the prefwindow element has two potentially useful functions to help in this regard:
onbeforeaccept
ondialogaccept
The former seems to have an associated bug (Bug 474527) that prevents the prefwindow from remaining open when returning false from that function. This is bad in that it doesn't give the user an opportunity to immediately correct their mistake.
The latter appears to have the problem that the preferences get saved prior to exiting, which leaves the preferences in a bad state internally.
In addition, the prefwindow mechanism supports the browser.preferences.instantApply option, in which preference values are written immediately upon updating the associated control. This makes validation extra tricky. Is there a clean way to validate custom preferences in a Firefox extension, allowing the user to correct any potential mistakes?
Normally you would want to validate the preferences when they are changed. That's something that onchange attribute (and the corresponding change event) is good for:
<preference name="preference.name" onchange="validate(this);"/>
The event is fired after the preference value changes. There are two drawbacks:
In case of instantApply the new preference value is already saved, too late to validate and decline.
For text fields the preferences are saved every time a new character is typed. This becomes ugly if you report validation failure while the user is still typing.
You can solve the first issue by intercepting the change events for the actual input fields. For example, for a text field you would do:
<input preference="preference.name"
oninput="if (!validate(this)) event.stopPropagation();"
onchange="if (!validate(this)) { event.stopPropagation(); this.focus(); }"/>
So changes that don't validate correctly don't bubble up to the <prefpane> element and don't get saved. The events to listen to are: input and change for text fields, command for buttons and checkboxes, select for the <colorpicker> element.
The second issue is tricky. You still want to validate the input when it happens, showing the message immediately would be bad UI however. I think that the best solution is to assume for each input field initially that it is still "in progress". You would only set a flag that the value is complete when you first see a blur event on the field. That's when you can show a validation message if necessary (ideally red text showing up in your preference page, not a modal prompt).
So to indicate what the final solution might look like (untested code but I used something like that in the past):
<description id="error" hidden="true">Invalid preference value</description>
<input preference="preference.name"
_errorText="error"
onblur="validate(event);"
oninput="validate(event);"
onchange="validate(event);/>
<script>
function validate(event)
{
// Perform actual validation
var field = event.target;
var valid = isValid(field);
// If this is the blur event then the element is no longer "in progress"
if (event.type == "blur")
{
field._inputDone = true;
if (!valid)
field.focus();
}
// Prevent preferences changing to invalid value
if (!valid)
event.stopPropagation();
// Show or hide error text
var errorText = document.getElementById(field.getAttribute("_errorText"));
errorText.hidden = valid || !field._inputDone;
}
</script>
If you want to validate values as soon as the field is changed so you can handle the instantApply case, you could hook into the change events for the individual fields (e.g. oninput for a textbox). Display an error message and force the focus back to the field if the value is invalid. You can either set it back to a valid value automatically or block the user from closing the dialog until it is fixed.

Resources