How to populate React-generated input fields with JQuery - javascript

I'm trying to write a bookmarklet to autofill a form, to simplify manual testing. The site is implemented in React. I've tried using JQuery, for example:
$("#emailAddress").val("bob#example.com").changed()
While the input field is visibly updated in the browser, it appears that under the hood the field is not recognised as changed, as validation fails on form submit, saying the data is missing.
Is there a workable way to autopopulate the React form fields using ad-hoc JS, without changing any of the source code?
(Note: I understand that this sort of direct manipulation is not the correct way to work with React in general app development. Here, I'm looking for any solution, no matter how hacky, to simplify ad-hoc manual testing).

//find element
let elem = document.querySelector("#emailAddress");
//create event
let event = new Event('input', { bubbles: true });
//set value
elem.value="bob#example.com";
//trigger event
elem.dispatchEvent(event)

From our discussion in the comments, my guess is that you'll want to fire a change event for each input you plan on modifying.
var element = document.getElementById('emailAddress'),
event = {
target: {
value: 'new value for the input'
}
};
element.onchange(event);

Related

Trigger jQuery when a vanilla js function has been fired

I got a jQuery function that catches changes on a input field and add it to a variable.
The input field is also held up on a vanilla js based API lib, that I cant convert to jQuery.
The lib is an address API, so people can select a address, and that wont trigger my jQuery function. I therefore thought of a workaround, where my jQuery is watching my vanilla js, to see when it's fired, and fire my jQuery function right after.
My jQuery function:
$('#billing_address_1').on('input',function(e){
let addressValue = $('#billing_address_1').val();
});
My vanilla js function:
"use strict"
dawaAutocomplete.dawaAutocomplete( document.getElementById("billing_address_1"), {
select: function(selected) {
document.getElementById("valgtadresse").innerHTML = selected.tekst;
}
});
All solutions I've been able to search for, has been requiring that I use .trigger() on my vanilla js in this case. They've not been made for the mix of these two js alternatives. Can I do it in a more proper way?
If you don't want to touch your fields with trigger you can try event emitter pattern which is quite popular in node. Here you keep an object as notifier on which you call event and also hook listeners for that event. It is basically a Pub-Sub pattern a simple implementation of which in vanilla javascript is available over here by mudge or you might also try any alternatives if you find
// KEEP THIS SOMEWHERE IN OUTER SCOPE
let bird = new EventEmitter()
//THEN - hook on any event you name it
bird.on('tweet', (val)=>{
console.log(val)
addressValue = val
})
//THEN - emit that named event wherever you might need
dawaAutocomplete.dawaAutocomplete( document.getElementById("billing_address_1"), {
select: function(selected) {
document.getElementById("valgtadresse").innerHTML = selected.tekst;
bird.emit('tweet', selected.tekst);
}
});

Dispatch event handlers fetched from Database as string

I am working on a form builder application. I need to store the events for the particular element into the database at design level and retrieve the events when the form is in published state.
I am storing the events as follows and this is example with more than one event for a control:
Structure of saving events in Database for one element:
{
Event:
{
EventType: "click",
EventHandler: "var i = 0; alert(i);"
},
Event:
{
EventType: "change",
EventHandler: "var i = 0; alert(i);"
}
}
Example HTML Code:
I am giving an example for textbox control in a form builder.
<input type="text" id="text1" />
On publishing the built form, I need to bind the above events for the built form which contains only one textbox.
Current Approach:
What I did is, I used eval() to execute the code and my code is as follows:
function BindEventsForControl(controlId,eventType,eventHandlerValue){
//Contruct the event string
var scriptString = "$(document).on('"+ eventType +"',"'+ controlId +"',function(){"+ eventHandlerValue +"});"
//Evaluate the above expression
eval(scriptString);
}
The above method works perfectly.
My concern:
I need to call BindEventsForControl() for each control in a form and need to use eval() many times. Is this feasible ?
My question:
Is my approach feasible ? Is there any better approach out there? Again, I am mentioning I want to execute the events stored as string.
If you know anyother new method, then kindly help me with that.
Also, I am using Knockout.js in my application. Is there any way to approach with knockout.js for these kind of scenario ?

Adding an event handler inside a knockoutjs custom binding

I'm a fairly experienced knockout user, so I understand quite a bit of the under the hood stuff, I have however been battling now for a few days trying to figure out how to achieve a given scenario.
I have to create a system that allows observable's within a given knockout component to be able to translate themselves to different languages.
to facilitate this, I've created a custom binding, which is applied to a given element in the following way.
<p data-bind="translatedText: {observable: translatedStringFour, translationToken: 'testUiTransFour'}"></p>
This is in turn attached to a property in my knockout component with a simple standard observable
private translatedStringFour: KnockoutObservable<string> = ko.observable<string>("I'm an untranslated string four....");
(YES, I am using typescript for the project, but TS/JS either I can work with.....)
With my custom binding I can still do 'translatedStringFour("foo")' and it will still update in exactly the same way as the normal text binding.
Where storing the translations in the HTML5 localStorage key/value store, and right at the beginning when our app is launched, there is another component that's responsible, for taking a list of translation ID's and requesting the translated strings from our app, based on the users chosen language.
These strings are then stored in localStorage using the translationToken (seen in the binding) as the key.
This means that when the page loads, and our custom bind fires, we can grab the translationToken off the binding, and interrogate localStorage to ask for the value to replace the untranslated string with, the code for our custom binding follows:
ko.bindingHandlers.translatedText = {
init: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
// Get our custom binding values
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
},
update: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
// Get our custom binding values
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
// Ask local storage if we have a token by that name
var translatedText = sessionStorage[translationToken];
// Check if our translated text is defined, if it's not then substitute it for a fixed string that will
// be seen in the UI (We should really not change this but this is for dev purposes so we can see whats missing)
if (undefined === translatedText) {
translatedText = "No Translation ID";
}
associatedObservable(translatedText);
ko.utils.setTextContent(element, associatedObservable());
}
}
Now, thus far this works brilliantly, as long as the full cache of translations has been loaded into localStorage, the observables will self translate with the correct strings as needed.
HOWEVER......
Because this translation loader may take more than a few seconds, and the initial page that it's loading on also needs to have some elements translated, the first time the page is loaded it is very possible that the translations the UI is asking for have not yet been loaded into into localStorage, or may be in the process of still loading.
Handling this is not a big deal, I'm performing the load using a promise, so the load takes place, my then clause fires, and I do something like
window.postMessage(...);
or
someElement.dispatchEvent(...);
or even (my favorite)
ko.postbox.publish(...)
The point here is I have no shortage of ways to raise an event/message of some description to notify the page and/or it's components that the translations have finished loading, and you are free to retry requesting them if you so wish.
HERE IN.... Lies my problem.
I need the event/message handler that receives this message to live inside the binding handler, so that the very act of me "binding" using our custom binding, will add the ability for this element to receive this event/message, and be able to retry.
This is not a problem for other pages in the application, because by the time the user has logged in, and all that jazz the translations will have loaded and be safely stored in local storage.
I'm more than happy to use post box (Absolutely awesome job by the way Ryan -- if your reading this.... it's an amazingly useful plugin, and should be built into the core IMHO) but, I intend to wrap this binding in a stand alone class which I'll then just load with requireJs as needed, by those components that need it. I cannot however guarantee that postbox will be loaded before or even at the same instant the binding is loaded.
Every other approach i've tried to get an event listener working in the binding have just gotten ignored, no errors or anything, they just don't fire.
I've tried using the postmessage api, I've tried using a custom event, I've even tried abusing JQuery, and all to no avail.
I've scoured the KO source code, specifically the event binding, and the closest I've come to attaching an event in the init handler is as follows:
init: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
// Get our custom binding values
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
// Set up an event handler that will respond to events on session storage, by doing this
// the custom binding will instantly update when a key matching it's translation ID is loaded into the
// local session store
//ko.utils.registerEventHandler(element, 'storage', (event) => {
// console.log("Storage event");
// console.log(event);
//});
ko.utils.registerEventHandler(element, 'customEvent', (event) => {
console.log("HTML5 custom event recieved in the binding handler.");
console.log(event);
});
},
None of this has worked, so folks of the Knockout community.....
How do I add an event handler inside of a custom binding, that I can then trigger from outside that binding, but without depending on anything other than Knockout core and my binding being loaded.
Shawty
Update (About an hour later)
I wanted to add this part, beacuse it's not 100% clear why Regis's answer solves my problem.
Effectively, I was using exactly the same method, BUT (and this is the crucial part) I was targeting the "element" that came in as part of the binding.
This is my mind was the correct approach, as I wanted the event to stick specifically with the element the binding was applied too, as it was said element that I wanted to re-try it's translation once it knew it had the go-ahead.
However, after looking at Regis's code, and comparing it to mine, I noticed he was attaching his event handlers to the "Window" object, and not the "Element".
Following up on this, I too changed my code to use the window object, and everything I'd been attempting started to work.
More's the point, the element specific targeting works too, so I get the actual event, on the actual element, in the actual binding that needs to re-try it's translation.
[EDIT: trying to better answer the question]
I don't really get the whole point of the question, since I don't see how sessionStorage load can be asynchronous.
I supposed therefore sessionStorage is populated from som asynchronous functions like an ajax call to a translation API.
But I don't see what blocks you here, since you already have all the code in your question:
var sessionStorageMock = { // mandatory to mock in code snippets: initially empty
};
var counter = 0;
var attemptTranslation = function() {
setInterval(function() { // let's say it performs some AJAX calls which result is cached in the sessionStorage
var token = "token"; // that should be a collection
sessionStorageMock[token] = "after translation " + (counter++); // we're done, notifying event handlers
window.dispatchEvent(new Event("translation-" + token));
}, 500);
};
ko.bindingHandlers.translated = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var val = valueAccessor();
var token = val.token;
console.log("init");
window.addEventListener("translation-" + token, function() {
if (token && sessionStorageMock[token]) {
val.observable(sessionStorageMock[token]);
}
});
}
};
var vm = function() {
this.aftertranslation = ko.observable("before translation");
};
ko.applyBindings(new vm());
attemptTranslation();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="translated: { observable: aftertranslation, token: 'token' }, text: aftertranslation" />

Simulating text entry with reactJs TestUtils

I want to be able to simulate a user typing into a text box using reactjs so that I can test my validation status messages.
I have a react component which validates on keyUp
Below is a simple example of what I've tried.
nameInput.props.value = 'a';
React.addons.TestUtils.Simulate.keyUp(nameInput);
React.addons.TestUtils.findRenderedDOMComponentWithClass(component, 'has-error');
This doesn't seem to change the value of the bound textbox when I debug in the validator
React.addons.TestUtils.Simulate.keyUp(nameInput, {key: 'a'});
React.addons.TestUtils.findRenderedDOMComponentWithClass(component, 'has-error');
This doesn't either.
Could someone point me on the right track, the second is inline with the documentation I could find around simulate (http://facebook.github.io/react/docs/test-utils.html), the first makes sense to me (set the actual textbox value then fake an event)
By setting nameInput.props.value = 'a'; you are not actually updating the value in your component.
You should use React.addons.TestUtils.Simulate.change(nameInput, { target: { value: 'a' } }); or something similar to simulate modifying the actual value.
I found that this syntax works better for me:
const emailInput = component.refs.userEmailInput;
emailInput.value = 'test#gmail.com';
Simulate.change(component.refs.userEmailInput);
The second line updates the input with the text, 'test#gmail.com'. The last line triggers the change.

Unit test controller that depends on form validation in AngularJS

In my controller I want to invoke an action (say on Tab press) only when form is valid. Also I need to clear form as soon as form gets submitted succesfully. I have something like this
app.controller('CommentFormController', function($scope) {
$scope.submit = function() {
if($scope.commentForm.$valid) {
// submit form
$scope.comment = '';
$scope.commentForm.$setPristine();
}
}
});
I'd like to test this, but it looks like I have to create this $scope.contactForm by hand and stub out $setPristine() function.
Is there any other way to test it? I mean can I somehow get instance of underlying FormController in my test?
How do you handle such cases?
Setting the form to pristine will affect the state of the form but won't reset the form to your defaults values (if you've provided them). Instead you can use the DOM element method reset().
Something like this:
document.getElementById("yourform").reset();
or, since angularJS and jQuery play nicely, you can use css selectors (especially useful if you have multiple forms you want to clear at once.
So something like:
$("#yourform")[0].reset();
There are pure javascript ways to do it also:
http://www.javascript-coder.com/javascript-form/javascript-reset-form.phtml
--- So in summary, you don't need to use specific methods to do this, simply use the DOM methods, jQuery, or pure javascript. Google will probably come out with a way to do this soon. Hope this helps.
#grafthez I got same problem when try validate the form is valid in my controller by $scope.myForm.$valid.
I found a solution on https://stackoverflow.com/a/17129354. You can try to inject $compile then $compile(yourFormTemplate)($scope).

Categories

Resources