Multiple text-areas being added after an update event - javascript

I am making a simple code editor using codemirror. I am at the last stage but a bug has occurred which I am not able to get my heads around.
I have a select html tag with three options:
<select class="language" id="lang" onclick="update()">
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="python">C</option>
</select>
And my update() function is:
function update() {
var select = $('#lang').val();
var editor = CodeMirror.fromTextArea($('#text'), {
mode: select,
theme: "blackboard",
});
}
update();
Now what happens is that everytime I select a different option from the dropdown, a new Code editor is added below the previous one.
Do you have some idea where I am going wrong in the code and how I can workaround?

Change your JS to this:
let editor;
function update() {
var select = $('#lang').val();
editor = editor ?? CodeMirror.fromTextArea($('#text'), {
theme: "blackboard",
});
editor.setOption('mode', select);
}
update();
This makes it so if editor already exists, it is not created again, but instead re-used.

Related

GoJS Diagram not loading at initial call

I have been trying to load a graph from a default selected value in a drop down list. This is the html for the select element.
<select class="custom-select" id="activity">
<option disabled value="">Select an activity</option>
<option selected value="Running">Running</option>
</select>
And then the javascript goes like this.
function loop() {
setTimeout(function () {
load(activities.value);
loop();
}, 5000);
}
var activities = document.getElementById("activity");
load(activities.value);
I tried this and the graph just dows not not load up. But then i tried this
function loop() {
setTimeout(function () {
load(activities.value);
loop();
}, 5000);
}
var activities = document.getElementById("activity");
load(activities.value);
loop();
function load(activity){
graph= {"class": "go.GraphLinksModel",
"nodeDataArray": [{}],
"linkDataArray": [{}]
}
myDiagram.model = go.Model.fromJson(graph);
}
And the initial function call just before loop() does not load the graph. But after 5 seconds once the loop kicks in the graph loads up. And every 5 seconds it keeps loading up just like it should. I also tried adding a onchange event listener to the drop down with 2 more options and added.
activities.addEventListener("change", () => {
load(activities.value);});
and once i changed back and forth the graphs load up.
I also tried the myDiagram.requestUpdate(); right after the load(activities.value);.
Where an going wrong? What am i doing wrong?. Appreciate all advices and questions for any more clarification and ofcourse some answers if anyone can help.
I found the solution to be the problem to be the load function initially being called before the div element is available. After adding a window.addEventListener('DOMContentLoaded', init); it is working fine now.

angular select element looses data when calling ngrenderer.selectRootElement

I have a select element:
<select [id]="item.value.controlName" [(ngModel)]="item.value.outputVarianteValue"
(focus)="focusControl(item.value.controlName)"
<option *ngFor="let c of item.value.produkte" [ngValue]="c.name">{{c.wert}}</option>
</select>
I rebuild my GUI programmaticaly and want to reset the focus to the element selected before (focusedcontrol)
setTimeout(() => {
const element = this.ngrenderer.selectRootElement('#' + this.focusedControl);
console.log('set root focus: ', this.focusedControl, element)
element.focus();
}, 0)
This works without a problem on normal inputs but not on the selects. After callling ngrenderer.selectRootElement(#myselect) my select field is empty.
answer is here:
Renderer multiple selectRootElement Issue
If you want to preserve content then use the second boolean parameter
to true, like this: (using Angular 6+)

cannot get dynamic added custom select to work in jQuery Mobile

I have looked through all of the similar questions available at the time of this question, and none of the solutions presented worked in the below code. Google was also not helpful except that I did find a few issues with dynamic code where the entire menu was not wrapped, but those issues should be fixed with either the trigger or enhanceWithin methods - which have been tried here.
I am a fairly new with javascript and the jquery library and this is my first app with jquery mobile.
The raw html as generated from the php file:
<div class="cell_container force_org_select">
<label for"force_org[new_555]" class="ui-hidden-accessible">Troop Type</label>
<select name="force_org[new_555]" id="force_org[new_555]" class="roster_cell" data-mini="true">
<option value="hq">HQ</option>
<option value="elite">Elite</option>
<option value="solo">Solitaire</option>
<option value="formation">Std Formation</option>
</select>
The Javascript function that handles the dynamic injection:
$(document).on('click','.add_item', function(event) {
event.preventDefault();
var the_link = $(this).attr('href')
var area = getParameterByName(the_link, 'area');
var type = getParameterByName(the_link, 'type');
var squad_id = getParameterByName(the_link, 'squad_id');
var vehicle = getParameterByName(the_link, 'vehicle');
var divider = getParameterByName(the_link, 'divider');
var preset = $('#preset').val();
$.post(cmd_ajax.ajaxurl,{action: 'cmd_add_item_mobile', type: type, preset: preset, squad_id: squad_id, vehicle: vehicle, divider: divider}, function(data) {
if(type == 'squad' || type == 'divider') {
$('#list').append(data).enhanceWithin();
//$('#list').append(data).trigger("refresh");
//$('#list').append(data).trigger("create");
$('.squad_help_button').tooltipster({
contentCloning: true,
trigger: 'custom',
triggerOpen: {
click: true,
tap: true
},
triggerClose: {
click: true,
tap: true
}
});
}
else {
$('#' + area).append(data).enhanceWithin();
}
//console.log("squad_id:"+this_id);
set_unit_sortable();
});
return false;
});
I also tried adding the .selectmenu("refresh",true) within the function and that seems to do nothing. The custom selects that are not dynamically generated work fine.
If I use the data-native-menu="false" attribute on the generated select menus, the popup does not function and you cannot select anything, if I remove the attribute, the native select works as it should.
I thought about using a selectmenu() refresh at the very end of the function, but I can't seem to catch the element id of the select menu either. My only guess is that it isn't created yet in the DOM when I try to retrieve it.

How to select option in drop down protractorjs e2e tests

I am trying to select an option from a drop down for the angular e2e tests using protractor.
Here is the code snippet of the select option:
<select id="locregion" class="create_select ng-pristine ng-invalid ng-invalid-required" required="" ng-disabled="organization.id !== undefined" ng-options="o.id as o.name for o in organizations" ng-model="organization.parent_id">
<option value="?" selected="selected"></option>
<option value="0">Ranjans Mobile Testing</option>
<option value="1">BeaverBox Testing</option>
<option value="2">BadgerBox</option>
<option value="3">CritterCase</option>
<option value="4">BoxLox</option>
<option value="5">BooBoBum</option>
</select>
I have tried:
ptor.findElement(protractor.By.css('select option:1')).click();
This gives me the following error:
An invalid or illegal string was specified
Build info: version: '2.35.0', revision: 'c916b9d', time: '2013-08-12 15:42:01'
System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9', java.version: '1.6.0_65'
Driver info: driver.version: unknown
I have also tried:
ptor.findElement(protractor.By.xpath('/html/body/div[2]/div/div[4]/div/div/div/div[3]/ng-include/div/div[2]/div/div/organization-form/form/div[2]/select/option[3]')).click();
This gives me the following error:
ElementNotVisibleError: Element is not currently visible and so may not be interacted with
Command duration or timeout: 9 milliseconds
Build info: version: '2.35.0', revision: 'c916b9d', time: '2013-08-12 15:42:01'
System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9', java.version: '1.6.0_65'
Session ID: bdeb8088-d8ad-0f49-aad9-82201c45c63f
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities [{platform=MAC, acceptSslCerts=true, javascriptEnabled=true, browserName=firefox, rotatable=false, locationContextEnabled=true, version=24.0, cssSelectorsEnabled=true, databaseEnabled=true, handlesAlerts=true, browserConnectionEnabled=true, nativeEvents=false, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]
Can anyone please help me with this problem or throw some light on what i might be doing wrong here.
For me worked like a charm
element(by.cssContainingText('option', 'BeaverBox Testing')).click();
I had a similar problem, and eventually wrote a helper function that selects dropdown values.
I eventually decided that I was fine selecting by option number, and therefore wrote a method that takes an element and the optionNumber, and selects that optionNumber. If the optionNumber is null it selects nothing (leaving the dropdown unselected).
var selectDropdownbyNum = function ( element, optionNum ) {
if (optionNum){
var options = element.all(by.tagName('option'))
.then(function(options){
options[optionNum].click();
});
}
};
I wrote a blog post if you want more detail, it also covers verifying the text of the selected option in a dropdown: http://technpol.wordpress.com/2013/12/01/protractor-and-dropdowns-validation/
An elegant approach would involve making an abstraction similar to what other selenium language bindings offer out-of-the-box (e.g. Select class in Python or Java).
Let's make a convenient wrapper and hide implementation details inside:
var SelectWrapper = function(selector) {
this.webElement = element(selector);
};
SelectWrapper.prototype.getOptions = function() {
return this.webElement.all(by.tagName('option'));
};
SelectWrapper.prototype.getSelectedOptions = function() {
return this.webElement.all(by.css('option[selected="selected"]'));
};
SelectWrapper.prototype.selectByValue = function(value) {
return this.webElement.all(by.css('option[value="' + value + '"]')).click();
};
SelectWrapper.prototype.selectByPartialText = function(text) {
return this.webElement.all(by.cssContainingText('option', text)).click();
};
SelectWrapper.prototype.selectByText = function(text) {
return this.webElement.all(by.xpath('option[.="' + text + '"]')).click();
};
module.exports = SelectWrapper;
Usage example (note how readable and easy-to-use it is):
var SelectWrapper = require('select-wrapper');
var mySelect = new SelectWrapper(by.id('locregion'));
# select an option by value
mySelect.selectByValue('4');
# select by visible text
mySelect.selectByText('BoxLox');
Solution taken from the following topic: Select -> option abstraction.
FYI, created a feature request: Select -> option abstraction.
element(by.model('parent_id')).sendKeys('BKN01');
To access a specific option you need to provide the nth-child() selector:
ptor.findElement(protractor.By.css('select option:nth-child(1)')).click();
This is how i did my selection.
function switchType(typeName) {
$('.dropdown').element(By.cssContainingText('option', typeName)).click();
};
Here's how I did it:
$('select').click();
$('select option=["' + optionInputFromFunction + '"]').click();
// This looks useless but it slows down the click event
// long enough to register a change in Angular.
browser.actions().mouseDown().mouseUp().perform();
Try this, it is working for me:
element(by.model('formModel.client'))
.all(by.tagName('option'))
.get(120)
.click();
You can try this hope it will work
element.all(by.id('locregion')).then(function(selectItem) {
expect(selectItem[0].getText()).toEqual('Ranjans Mobile Testing')
selectItem[0].click(); //will click on first item
selectItem[3].click(); //will click on fourth item
});
Another way to set an option element:
var select = element(by.model('organization.parent_id'));
select.$('[value="1"]').click();
To select items (options) with unique ids like in here:
<select
ng-model="foo"
ng-options="bar as bar.title for bar in bars track by bar.id">
</select>
I'm using this:
element(by.css('[value="' + neededBarId+ '"]')).click();
We wrote a library which includes 3 ways to select an option:
selectOption(option: ElementFinder |Locator | string, timeout?: number): Promise<void>
selectOptionByIndex(select: ElementFinder | Locator | string, index: number, timeout?: number): Promise<void>
selectOptionByText(select: ElementFinder | Locator | string, text: string, timeout?: number): Promise<void>
Additional feature of this functions is that they wait for the element to be displayed before any action on the select is performed.
You can find it on npm #hetznercloud/protractor-test-helper.
Typings for TypeScript are provided as well.
Maybe not super elegant, but efficient:
function selectOption(modelSelector, index) {
for (var i=0; i<index; i++){
element(by.model(modelSelector)).sendKeys("\uE015");
}
}
This just sends key down on the select you want, in our case, we are using modelSelector but obviously you can use any other selector.
Then in my page object model:
selectMyOption: function (optionNum) {
selectOption('myOption', optionNum)
}
And from the test:
myPage.selectMyOption(1);
The problem is that solutions that work on regular angular select boxes do not work with Angular Material md-select and md-option using protractor. This one was posted by another, but it worked for me and I am unable to comment on his post yet (only 23 rep points). Also, I cleaned it up a bit, instead of browser.sleep, I used browser.waitForAngular();
element.all(by.css('md-select')).each(function (eachElement, index) {
eachElement.click(); // select the <select>
browser.waitForAngular(); // wait for the renderings to take effect
element(by.css('md-option')).click(); // select the first md-option
browser.waitForAngular(); // wait for the renderings to take effect
});
There's an issue with selecting options in Firefox that Droogans's hack fixes that I want to mention here explicitly, hoping it might save someone some trouble: https://github.com/angular/protractor/issues/480.
Even if your tests are passing locally with Firefox, you might find that they're failing on CircleCI or TravisCI or whatever you're using for CI&deployment. Being aware of this problem from the beginning would have saved me a lot of time:)
Helper to set the an option element:
selectDropDownByText:function(optionValue) {
element(by.cssContainingText('option', optionValue)).click(); //optionValue: dropDownOption
}
If below is the given dropdown-
<select ng-model="operator">
<option value="name">Addition</option>
<option value="age">Division</option>
</select>
Then protractorjs code can be-
var operators=element(by.model('operator'));
operators.$('[value=Addition]').click();
Source-https://github.com/angular/protractor/issues/600
Select option by Index:
var selectDropdownElement= element(by.id('select-dropdown'));
selectDropdownElement.all(by.tagName('option'))
.then(function (options) {
options[0].click();
});
I've improved a bit the solution written by PaulL.
First of all I fixed the code to be compatible with the last Protractor API. And then I declare the function in 'onPrepare' section of a Protractor config file as a member of the browser instance, so it can be referenced form any e2e spec.
onPrepare: function() {
browser._selectDropdownbyNum = function (element, optionNum) {
/* A helper function to select in a dropdown control an option
* with specified number.
*/
return element.all(by.tagName('option')).then(
function(options) {
options[optionNum].click();
});
};
},
The below example is the easiest way . I have tested and passed in Protractor Version 5.4.2
//Drop down selection using option's visibility text
element(by.model('currency')).element(by.css("[value='Dollar']")).click();
Or use this, it $ isshort form for .By.css
element(by.model('currency')).$('[value="Dollar"]').click();
//To select using index
var select = element(by.id('userSelect'));
select.$('[value="1"]').click(); // To select using the index .$ means a shortcut to .By.css
Full code
describe('Protractor Demo App', function() {
it('should have a title', function() {
browser.driver.get('http://www.way2automation.com/angularjs-protractor/banking/#/');
expect(browser.getTitle()).toEqual('Protractor practice website - Banking App');
element(by.buttonText('Bank Manager Login')).click();
element(by.buttonText('Open Account')).click();
//Drop down selection using option's visibility text
element(by.model('currency')).element(by.css("[value='Dollar']")).click();
//This is a short form. $ in short form for .By.css
// element(by.model('currency')).$('[value="Dollar"]').click();
//To select using index
var select = element(by.id('userSelect'));
select.$('[value="1"]').click(); // To select using the index .$ means a shortcut to .By.css
element(by.buttonText("Process")).click();
browser.sleep(7500);// wait in miliseconds
browser.switchTo().alert().accept();
});
});
I've been trawling the net for an answer on how to select an option in a model dropdown and i've used this combination which has helped me out with Angular material.
element(by.model("ModelName")).click().element(By.xpath('xpathlocation')).click();
it appears that when throwing the code all in one line it could find the element in the dropdown.
Took a lot of time for this solution I hope that this helps someone out.
If none of the answer's above worked for you, try this
works with async/await too
For selecting options by text
let textOption = "option2"
await element(by.whichever('YOUR_DROPDOWN_SELECTOR'))
.getWebElement()
.findElement(by.xpath(`.//option[text()="${textOption}"]`))
.click();
or by number
let optionNumber = 2
await element(by.whichever('YOUR_DROPDOWN_SELECTOR'))
.getWebElement()
.findElement(by.xpath(`.//option[${optionNumber}]`))
.click();
Of course you may need to modify the xpath of child options
Don't ask me why, but this is the only way I could automate my dropdowns, when I lost hope already
Update
There was actually one case when even this approach didnt work. THe work around was a bit ugly but worked. I simply had to select the value two times
We wanted to use the elegant solution up there using angularjs material but it didnt work because there are actually no option / md-option tags in the DOM until the md-select has been clicked. So the "elegant" way didn't work for us (note angular material!) Here is what we did for it instead, don't know if its the best way but its definately working now
element.all(by.css('md-select')).each(function (eachElement, index) {
eachElement.click(); // select the <select>
browser.driver.sleep(500); // wait for the renderings to take effect
element(by.css('md-option')).click(); // select the first md-option
browser.driver.sleep(500); // wait for the renderings to take effect
});
We needed to have 4 selects selected and while the select is open, there is an overlay in the way of selecting the next select. thats why we need to wait 500ms to make sure we don't get into trouble with the material effects still being in action.
Another way to set an option element:
var setOption = function(optionToSelect) {
var select = element(by.id('locregion'));
select.click();
select.all(by.tagName('option')).filter(function(elem, index) {
return elem.getText().then(function(text) {
return text === optionToSelect;
});
}).then(function(filteredElements){
filteredElements[0].click();
});
};
// using the function
setOption('BeaverBox Testing');
----------
element.all(by.id('locregion')).then(function(Item)
{
// Item[x] = > // x is [0,1,2,3]element you want to click
Item[0].click(); //first item
Item[3].click(); // fourth item
expect(Item[0].getText()).toEqual('Ranjans Mobile Testing')
});
You can select dropdown options by value:
$('#locregion').$('[value="1"]').click();
Here is how to do it by either option value or index. This example is a bit crude, but it shows how to do what you want:
html:
<mat-form-field id="your-id">
<mat-select>
<mat-option [value]="1">1</mat-option>
<mat-option [value]="2">2</mat-option>
</mat-select>
</mat-form-field>
ts:
function selectOptionByOptionValue(selectFormFieldElementId, valueToFind) {
const formField = element(by.id(selectFormFieldElementId));
formField.click().then(() => {
formField.element(by.tagName('mat-select'))
.getAttribute('aria-owns').then((optionIdsString: string) => {
const optionIds = optionIdsString.split(' ');
for (let optionId of optionIds) {
const option = element(by.id(optionId));
option.getText().then((text) => {
if (text === valueToFind) {
option.click();
}
});
}
});
});
}
function selectOptionByOptionIndex(selectFormFieldElementId, index) {
const formField = element(by.id(selectFormFieldElementId));
formField.click().then(() => {
formField.element(by.tagName('mat-select'))
.getAttribute('aria-owns').then((optionIdsString: string) => {
const optionIds = optionIdsString.split(' ');
const optionId = optionIds[index];
const option = element(by.id(optionId));
option.click();
});
});
}
selectOptionByOptionValue('your-id', '1'); //selects first option
selectOptionByOptionIndex('your-id', 1); //selects second option
static selectDropdownValue(dropDownLocator,dropDownListLocator,dropDownValue){
let ListVal ='';
WebLibraryUtils.getElement('xpath',dropDownLocator).click()
WebLibraryUtils.getElements('xpath',dropDownListLocator).then(function(selectItem){
if(selectItem.length>0)
{
for( let i =0;i<=selectItem.length;i++)
{
if(selectItem[i]==dropDownValue)
{
console.log(selectItem[i])
selectItem[i].click();
}
}
}
})
}
We can create a custom DropDown class for this and add a method as:
async selectSingleValue(value: string) {
await this.element.element(by.xpath('.//option[normalize-space(.)=\'' + value + '\']')).click();
}
Also, to verify what value is currently selected, we can have:
async getSelectedValues() {
return await this.element.$('option:checked').getText();
}
This is a simple one line answer in which angular has special locator which can help to select and index from list.
element.all(by.options('o.id as o.name for o in organizations')).get(Index).click()

Data binding inside <option> element in angular.js and jQuery mobile

I have recently added a multi-language support to my jQuery-mobile/PhoneGap app using this great repo on gitHub.
It uses firebase and angular.js to bind all the language dependant labels and texts in my app to the currently selected language, like in this example:
<h2>{{getWord("SELECTION_CRITERIA")}}</h2>
However, there are some language-dependant texts in my app that cannot be simply bound to language data, I have found this so far:
<select id="sel" data-role="slider">
<option value="off">{{getWord("SELECT_OFF")}}</option>
<option value="on">{{getWord("SELECT_ON")}}</option>
</select>
The <option> element doesn't allow to bind it's text to the data (the rendered text is empty). I don't know why. I tried to test whether something like this could work:
<option value="off">{{1+2}}</option>
and yes, it displayed number 3 in the slider.
The angular.js part looks like this:
function LanguageCtrl($scope) {
$scope.words = JSON.parse('{}');
$scope.addWord = function(Name, Value) {
$scope.words[Name] = Value;
};
$scope.getWord = function(Name) {
return $scope.words[Name];
};
}
var ref;
var refLang;
var onLangChange;
$(document).on("pageinit", "#mainPage", function(event) {
ref = new Firebase('https://username.firebaseio.com/');
ChangeLangTo("En"); //default lang
});
function ChangeLangTo(lang) {
if (onLangChange !== undefined && onLangChange !== undefined) {
refLang.off('child_changed', onLangChange);
}
refLang = ref.child(lang);
//reading once all words
refLang.once('value', function(dataSnapshot) {
var lang = dataSnapshot.val();
angular.element($("#mainPage")).scope().$apply(function(scope) {
$.each(lang, function(key, value) {
scope.addWord(key, value);
});
});
});
//listening to changes
onLangChange = refLang.on('child_changed', function(childSnapshot, prevChildName) {
angular.element($("#mainPage")).scope().$apply(function(scope) {
scope.addWord(childSnapshot.name(), childSnapshot.val());
});
});
The JSON from firebase that is parsed into that variable is very simple, like:
{
"Cz": {
"SELECT_ON":"Ano",
"SELECT_OFF":"Ne"
},
"En": {
"SELECT_ON":"On",
"SELECT_OFF":"Off"
}
}
I think that the <button> element won't work, too. And there are some cases of setting an element text via an attribute, like in this case:
<ul data-filter-placeholder="Search items..."></ul>
I would like to make this work, too:
<ul data-filter-placeholder="{{getWord("SEARCH_ITEMS")}}"></ul>
I am very new to angular.js, can someone please explain me how to make this work? I have read some documentation on HTML SELECT element with angular data-binding, but do not quite understand how to apply it.
Thanks!

Categories