Bacon.js call function every time element loses focus - bacon.js

Update I think I might have it figured out. I was using an old bacon.js version, which might have been part of the problem. I'll update later as I figure out if I have it. Here's the partially working version: http://cdpn.io/yfxDA
I'm trying to call a function every time an element loses focus (an input but in the below example I'm using a div).
This is what I tried:
var $on = $('div')
$on.asEventStream('focusout').subscribe(alert('no!'))
and
var $on = $('div')
$on.asEventStream('focusout').onValue(alert('no!'))
They both work the first time but then stop working. Is there a way to get this to work?
Eventually I would like to merge focusin/focusout and perform a side-effect.

It looks like I just needed the most up to date version of the software. Here's what the code looks like now:
var $on = $('div')
var $h = $('div input')
var d = 'contains'
$h.val(d)
var f = function(arg){
return ($h.val() === d) ? '' : d
}
$on.asEventStream('focusout').merge($on.asEventStream('focusin')).toProperty().assign($h, 'val', f)

I works just fine with the latest version:
http://codepen.io/anon/pen/xLHyq

Related

Why does data in list1 changed automatically when I change the data in the other list2 which is cloned from the list1? Using Vue.Draggable

I am using Vue.Draggable in my Vue project and trying to drag(clone) a button from sider into a draggable component.
I want to modify the data when I clone the button into the component. But I find that when I modify the data in the list which is binded with the component, the original list that sider used got changed automatically.
Is there some kind of synchronization mechanism in Vue.Draggable or something? I want to change the object data in the component only.
I tried to modify the object in the list2 manually by using a vue extension in Chrome browser. And it still happens. So I think maybe it's not bug in my code.
addEntity (conditionID, entity) {
if (!entity.forChoose) {
}
else {
let variable = 0;
for (let i = 0, len = this.whens.length; i < len; i++) {
if (this.whens[i].entity[0].id == entity.id) {
variable++;
}
}
this.whens[conditionID].entity[0].forChoose = false;
this.whens[conditionID].entity[0].variable = variable;
this.whens[conditionID].entity[0].name = entity.name + '-fake';
}
},
The code above is the event when I drag the data into the component, and changed some variable.
Although I did nothing to the original data in the Sider where I cloned the data from, it still got changed as well.
Is there a way to change the dragged data but do not affect the original data?
Please help me, thank you!
I think this is happening because of the immutability.
so can you try using spread operator to create new shallow copy of your list before you change it.
how to use spread operator (triple dot)
let newArrayOfWhens = [...this.whens]
then use the "newArrayOfWhens" array in your code
You can create a deep clone as well if you want, but try to avoid it if it is not necessary.
you can use a library call "lodash" to do it very easily
deepClone

Selenium send keys incorrect order in Stripe credit card input

After sending keys to an input field with selenium, the result is not as expected - the keys are inserted in incorrect order.
e.g. send_keys('4242424242424242') -> result is "4224242424242424"
EDIT: On some machines I observe the issue only randomly, 1 case out of 10 attempts. On another machine it is 10/10
This happens specifically with Stripe payment form + I see this problem only in Chrome version 69 (in previous versions it worked OK)
This can be easily reproduced on sample Stripe site: https://stripe.github.io/elements-examples/
Sample python code:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://stripe.github.io/elements-examples/')
driver.switch_to.frame(driver.find_element_by_tag_name('iframe')) # First iframe
cc_input = driver.find_element_by_css_selector('input[name="cardnumber"]')
cc_input.send_keys('4242424242424242')
Result:
I am able to get pass this by sending the keys one by one with slight delay - but this is also not 100% reliable (plus terribly slow)
I am not sure if this is a problem with selenium (3.14.1)/chromedriver (2.41.578737) or if I am doing something wrong.
Any ideas please?
We are having the exact same problem on MacOS and Ubuntu 18.04, as well as on our CI server with protractor 5.4.1 and the same version of selenium and chromedriver. It has only started failing since Chrome 69, worse in v70.
Update - Working (for the moment)
After much further investigation, I remembered that React tends to override change/input events, and that the values in the credit card input, ccv input etc are being rendered from the React Component State, not from just the input value. So I started looking, and found What is the best way to trigger onchange event in react js
Our tests are working (for the moment):
//Example credit input
function creditCardInput (): ElementFinder {
return element(by.xpath('//input[contains(#name, "cardnumber")]'))
}
/// ... snippet of our method ...
await ensureCreditCardInputIsReady()
await stripeInput(creditCardInput, ccNumber)
await stripeInput(creditCardExpiry, ccExpiry)
await stripeInput(creditCardCvc, ccCvc)
await browser.wait(this.hasCreditCardZip(), undefined, 'Should have a credit card zip')
await stripeInput(creditCardZip, ccZip)
await browser.switchTo().defaultContent()
/// ... snip ...
async function ensureCreditCardInputIsReady (): Promise<void> {
await browser.wait(ExpectedConditions.presenceOf(paymentIFrame()), undefined, 'Should have a payment iframe')
await browser.switchTo().frame(await paymentIFrame().getWebElement())
await browser.wait(
ExpectedConditions.presenceOf(creditCardInput()),
undefined,
'Should have a credit card input'
)
}
/**
* SendKeys for the Stripe gateway was having issues in Chrome since version 69. Keys were coming in out of order,
* which resulted in failed tests.
*/
async function stripeInput (inputElement: Function, value: string): Promise<void> {
await browser.executeScript(`
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(arguments[0], '${value}');
var inputEvent = new Event('input', { bubbles: true});
arguments[0].dispatchEvent(inputEvent);
`, inputElement()
)
await browser.sleep(100)
const typedInValue = await inputElement().getWebElement().getAttribute('value')
if (typedInValue.replace(/\s/g, '') === value) {
return
}
throw new Error(`Failed set '${typedInValue}' on ${inputElement}`)
}
Previous Idea (only worked occasionally):
I have setup a minimal repro using https://stripe.com/docs/stripe-js/elements/quickstart and it succeeds when tests are run sequentially, but not in parallel (we think due to focus/blur issues when switching to the iframes).
Our solution is similar, although we noticed from watching the tests that input.clear() wasn't work on tel inputs which are used in the iframe.
This still fails occasionally, but far less frequently.
/**
* Types a value into an input field, and checks if the value of the input
* matches the expected value. If not, it attempts for `maxAttempts` times to
* type the value into the input again.
*
* This works around an issue with ChromeDriver where sendKeys() can send keys out of order,
* so a string like "0260" gets typed as "0206" for example.
*
* It also works around an issue with IEDriver where sendKeys() can press the SHIFT key too soon
* and cause letters or numbers to be converted to their SHIFT variants, "6" gets typed as "^", for example.
*/
export async function slowlyTypeOutField (
value: string,
inputElement: Function,
maxAttempts = 20
): Promise<void> {
for (let attemptNumber = 0; attemptNumber < maxAttempts; attemptNumber++) {
if (attemptNumber > 0) {
await browser.sleep(100)
}
/*
Executing a script seems to be a lot more reliable in setting these flaky fields than using the sendKeys built-in
method. However, I struggled in finding out which JavaScript events Stripe listens to. So we send the last key to
the input field to trigger all events we need.
*/
const firstPart = value.substring(0, value.length - 1)
const secondPart = value.substring(value.length - 1, value.length)
await browser.executeScript(`
arguments[0].focus();
arguments[0].value = "${firstPart}";
`,
inputElement()
)
await inputElement().sendKeys(secondPart)
const typedInValue = await inputElement().getAttribute('value')
if (typedInValue === value) {
return
}
console.log(`Tried to set value ${value}, but instead set ${typedInValue} on ${inputElement}`)
}
throw new Error(`Failed after ${maxAttempts} attempts to set value on ${inputElement}`)
}
I faced a similar issue in ubuntu 14.04, the following trick helped me.
Have not got any issue since.
First I used the regular send_keys method.
Then I called the execute script to update the value
input_data = "someimputdata"
some_xpath = "//*[contains(#id,'input_fax.number_')]"
element = web_driver_obj.find_element_by_xpath(some_xpath)
element.clear()
element.send_keys(input_data)
web_driver_obj.execute_script("arguments[0].value = '{0}';".format(input_data), element)
Edit
Thanks a lot to #Benno - his answer was correct.
I will just add python solution that worked for me, based on his JS
driver.get('https://stripe.github.io/elements-examples/')
driver.switch_to.frame(driver.find_element_by_tag_name('iframe')) # First iframe
cc_input = driver.find_element_by_css_selector('input[name="cardnumber"]')
value = "4242424242424242"
driver.execute_script('''
input = arguments[0];
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, "{}");
var eventCard = new Event("input", {{bubbles: true}});
input.dispatchEvent(eventCard);
'''.format(value), cc_input)
driver.switch_to.default_content()
driver.quit()
After couple of hours of trying, I gave up and accepted the fact that this is really a random issue and went with a workaround.
Where it is not necessary to update, I will stay with Chrome version < 69
In order to test latest Chrome, I will use React solution
What I've found out
The issue manifested itself mostly on MacOS, quite rarely on Windows (there are most probably other factors in play, this is just an observation)
I've run an experiment with 100 repetitions of filling the form.
Mac - 68 failures
Windows - 6 failures
The cookies/local history (as suggested in comments) do not seem to be the problem. The webdriver always spawned a "clean" instance of the browser, with no cookies or local storage.
Maybe my solution will help for somebody:
I used sendKeys(" 4242424242424242")
Same for cvc field
With a space before string, it actually works for selenide + chrome + java
You could make your own generic SendKeys method that takes the input element and the string you would like to send. The method would split the string into individual characters and then use the selenium sendkeys method on each character.
Adding in some backspaces worked for me for whatever reason:
from selenium.webdriver.common.keys import Keys
my_value = "123"
my_xpath="//input[#class='form-text']"
element = driver.find_element_by_xpath(my_xpath)
element.clear()
element.send_keys(Keys.BACKSPACE * 3, my_value)
I was having the same issue using RSelenium and got the idea to try adding spaces to the credit card number as they appear on the card from #Pavel's answer, since adding a space before the card number didn't work for me.
Using RSelenium this would be:
element$sendKeysToElement(list("4242 4242 4242 4242"))

MatPagination: mat-table does not update item limit when changing MatPaginator

I am trying to paginate my table.
I have the full implementation of Angular Material Table with Pagination(https://material.angular.io/components/table/overview#pagination)
Since I am using Angularfire2 my dataSource is an Observable.
this.items = this.itemsCollection.valueChanges();
I read that I have to use
dataSource = new MatTableDataSource<Item>;
to create a working connection between table and paginator.
I populate the dataSource by
let subscription = this.items.subscribe(
newData => { this.dataSource.data = newData });
and update the dataSource's paginator by
ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
}
where this.paginator is defined by
#ViewChild(MatPaginator) paginator: MatPaginator
like explained in Angular Material's components doc.
The paginator(mat-paginator) is working fine. However, my issue is that the table does not refresh and continues to show all values. Initial values to 'this.paginator' are also not passed to the table limit.
I found a known bug, but I am not sure if that applies to my problem...
Can anyone help me out?
Thank you in advanced!!
Update
I found an easy solution for my problem by using the Angular Pipe at mat-table. I added the slice pipe like this:
<mat-table #table [dataSource]="dataObservable | async | slice: a:b">
and in my data component I was listening to the change event of the HTML Element "mat-paginator"
(page)="changePage($event)"
In my component I can easily set the sliced data
a = 0;
b = this.limit;
changePage(ev) {
console.log( ev );
this.a = ev.pageIndex * ev.pageSize;
this.b = this.a + ev.pageSize;
console.log(this.a);
console.log(this.b);
}

extjs 4.1 how to reset the itemselector

I am using extjs 4.1.1a for developing some application.
I had a form consisting of two combo-boxes and an item-selector.
Based on the value selected in first combo-box , the itemselector will load its data from database. This is working fine.
My problem is, if i reselect the first combo-box the new data will be displayed in itemselector along with previous data displayed in itemseletor .That is previous data displayed in itemselector will remain there itself.
for example: name "test1" consists of ids 801,2088,5000. on selecting test1 in firstcombobox itemselector must show output as below.
and if "test2" consists of ids 6090,5040. on selecting test2 in firstcombobox itemselector must show output as below.
problem is. for first time if i select "test1" from firstcombobox , output will come as expected. if i reselect "test2" from firstcombobox , output will come as below.
as you can see, previous data displayed (marked in red rectagle) remains there itself with new data displayed (marked with green rectangle).
I want for every reselection of first combobox, previously displayed data in itemselector to be erased before printing new data on itemselector.
How can I reset the itemselector for every reselection of first combobox?
You should remove all items from the store of the itemselector by the removeAll command. After that you should load the store of the itemselector.
itemselector.store.removeAll();
itemselector.store.load();
Any solutions above solve my problem.
i found solution from Sencha Forum.
https://www.sencha.com/forum/showthread.php?142276-closed-Ext-JS-4.0.2a-itemselector-not-reloading-the-store
in the itemselector.js file, change the line marked below.
populateFromStore: function(store) {
var fromStore = this.fromField.store;
// Flag set when the fromStore has been loaded
this.fromStorePopulated = true;
// THIS LINE BELOW MUST BE CHANGED!!!!!!!!!!!!
fromStore.loadData(store.getRange()); //fromStore.add(store.getRange());
// setValue waits for the from Store to be loaded
fromStore.fireEvent('load', fromStore);
},
You need to insert...
this.reset();
at the head of the function that is inserting the data.
As an example...
Ext.override( Ext.ux.ItemSelector, {
setValue: function(val) {
this.reset();
if (!val) return;
val = val instanceof Array ? val : val.split(this.delimiter);
var rec, i, id;
for (i = 0; i < val.length; i++) {
var vf = this.fromMultiselect.valueField;
id = val[i];
idx = this.toMultiselect.view.store.findBy(function(record){
return record.data[vf] == id;
});
if (idx != -1) continue;
idx = this.fromMultiselect.view.store.findBy(function(record){
return record.data[vf] == id;
});
rec = this.fromMultiselect.view.store.getAt(idx);
if (rec) {
this.toMultiselect.view.store.add(rec);
this.fromMultiselect.view.store.remove(rec);
}
}
}
});
are u got it?
when u select that combobox frist stoe of item selector is null after store load with ur pass the para meters
for example
store.load(null),
store.proxey.url='jso.php?id='+combobox.getrawvalue(),
store.load();
like that so when ur select a value in ur combobox that time ur used a listeners to ur combobox in that listners ur used above code , select ur some value in combobox that time frist store is get null after ur pass some values to json.php then store load with responce so that time old data is remove and new data load in that store
if u post ur code i will give correct code
I ran into the same issue with ExtJS 4.2.1. I got it to work by calling reload() on the data store and then setValue() with an empty string on the item selector in the data store's reload() callback.
Ext.create("Ext.form.field.ComboBox", {
// Other properties removed for brevity
listeners: {
change: function(field, newValue, oldValue, eOpts) {
Ext.getStore("ExampleStore").reload({
callback: function() {
Ext.getCmp("ExampleItemSelector").setValue("");
}
});
}
}
});
Ext.create("Ext.data.Store", {
storeId: "ExampleStore",
// Other properties removed for brevity
});
Ext.create("Ext.form.FormPanel", {
// Other properties removed for brevity
items:[{
xtype: "itemselector",
id: "ExampleItemSelector",
// Other properties removed for brevity
}]
});
For any folks that are curious, I'm fairly convinced there's a bug in the item selector's populateFromStore() function. When the function is called, it blindly adds all of the values from the bound store (store) to the internal store (fromStore). I suspect there should be a call to fromStore.removeAll() prior to the call to fromStore.add(). Here's the relevant code from ItemSelector.js.
populateFromStore: function(store) {
var fromStore = this.fromField.store;
// Flag set when the fromStore has been loaded
this.fromStorePopulated = true;
fromStore.add(store.getRange());
// setValue waits for the from Store to be loaded
fromStore.fireEvent('load', fromStore);
},
EDIT 12/18/2013
If you've configured any callback events on the item selector (e.g. change), you may want to disable the events temporarily when you call setValue(""). For example:
var selector = Ext.getCmp("ExampleItemSelector");
selector.suspendEvents();
selector.setValue("");
selector.resumeEvents();
I had the same problem and finally I decided to modify the extjs source code, not considering it a big issue as extjs itself its saying in the start of the file
Note that this control will most likely remain as an example, and not as a core Ext form
control. However, the API will be changing in a future release and so should not yet be
treated as a final, stable API at this time.
Based on that, as jstricker guessed (and sadly I didn't read and took me a while to arrive to the same conclusion), adding fromStore.removeAll() before fromStore.add() solves the problem.
Outside of the problem (but I think it can be interesting as well), additionally, I also added listConfig: me.listConfig in the MultiSelect configuration (inside createList), that way it's possible to format each item additional options (such as images, etc.) setting in the 'itemselector' the option listConfig as it's explained in the (irrealistic) documentation.
Need to reset the store used in ItemSelector that can be done by setting Empty object like below. Also need to call clearValue() method of ItemSelector component.
store.setData({});
ItemSelectorComponent.clearValue();

dojo/form/select onchange event not working for me in dojo 1.8

I am trying out dojotoolkit 1.8 and cant figure out how to hook up an onchange event for a dojo/form/select
Nothing happens with this
require(["dojo/dom","dojo/on"], function(dom,on){
on(dom.byId("myselect"),"change",function (evt){
alert("myselect_event");
});
If instead, the following hook into click works:
on(dom.byId("myselect"),"click",function (evt){
but i want to capture the value after user clicks and changes
I am sure it is simpler than going back to Plain ol javascript onChange...
Thx
You could try something like this:
var select = dijit.byId('myselect');
select.on('change', function(evt) {
alert('myselect_event');
});
I've seen this in the reference-guide multiple times, eg in the dijit/form/select' s reference-guide at 'A Select Fed By A Store'.
Maybe it even returnes the handle, i haven't looked this up so far. But i guess it should work.
EDIT:
Considering #phusick's comment, i want to add, that you could also simply change the "change" to "onChange" or the dom to dijit within calling on(...)
Following in the footsteps of #nozzleman's answer try
var select = registry.byId('myselect');
select.on('change', function(evt) {
alert('myselect_event');
});
If you use on instead of connect then you don't have to write onChange, you can simply write change.
Similar to above answers do a dijit.ById to find the correct element and then register the 'onItemClick' event.
creating the select dropdown programatically appends a _menu to whatever node you create the select items so 'search' becomes 'search_menu' on a page init you can do the following:
dojo.connect(dijit.byId('search_menu'),'onItemClick',function(){
//console.log("search menu");
doSearch('recreation');
});
As others have pointed out, you're trying to access the Dijit using DOM. Also, the parameter to the anonymous function for the "change" event is the value selected by the user, not the event itself.
Here's your code modified to access the Dijit and process the "change" event:
require(["dijit/registry", "dojo/on"], function(registry, on) {
on(registry.byId("myselect"), "change", function (value) {
alert("change_event.value = " + value);
});
});
Late to the party, but I recently ran into the issue. Hopefully my answer will help some poor soul maintaining some legacy code. The answer is for combobox but worked for select as well -
onChange not sufficient to trigger query from Dojo Combobox. Need to attach listener to dropdown items.
select.dropDown.on("itemClick", function(dijit, event) {
var node = dijit.domNode;
console.log(domAttr.get(node, "data-info-attribute"));
// or
console.log(node.dataset.infoAttribute);
});
Ref: https://stackoverflow.com/a/12422155/4564016