Currently I have a function that iterates through multiple divs, finds a div with the class name of ".courseArea", and return it to be appended by another
function getCourseAreaBySemester(sem_id) {
$(".semesterPanel").each(function() {
if($(this).attr('id') == sem_id) {
return $(this).find('.courseArea'));
}
});
}
Second function to process the return
var targetSemester = getCourseAreaBySemester(semesterData[i]['semester_id']);
console.log(targetSemester);
targetSemester.append(createCourse(semesterData['courses'][j]));
The console prints out "undefined", and therefore, I cannot do a .append().
But if I console.log right before the return, it returns [<ul class="courseArea"></ul>]
I know it works If I don't use the .each() function. However, I need to select by ID.
Does anyone know what is wrong here? Or of an alternative? Thanks
function getCourseAreaBySemester(sem_id) {
var result;
$(".semesterPanel").each(function() {
if($(this).attr('id') == sem_id) {
result = $(this).find('.courseArea'));
}
});
return result;
}
Returning the value of the inner function inside it obviously does not affect the return value of the getCourseAreaBySemester function!
You aren't returning anything from getCourseAreaBySemester. A return within each is closed and only returns within the each callback
You could simplify and just use the ID as selector since ID's in a page are unique:
function getCourseAreaBySemester(sem_id) {
return $('#'+sem_id).find('.courseArea');
}
Related
I have a 'select' element in a UI component from which I need to retrieve the selected option (if any). As a beginner in both JavaScript and protractor, I am having trouble figuring out how to accomplish this without a bunch of nested promises:
I have two locators -- one for the selector's current selection and one for all the options:
selector = element(by.model("something.someId"));
this.selectorOptions = element.all(by.repeater("repeat in someOptions | orderBy:'name'"));
getSelectedOption = function () {
return this.selector.getText().then( function (selectionText) {
return this.selectorOptions.filter(function (option) {
option.getText().then(function (optionText) {
if(optionText === selectionText) {
option.getAttribute("value").then(function (value) {
// Some logic here which uses the value to return an pojo representing the selection
})
}
})
})
})
};
The above is just awful and I am sure this can be done better. I have looked at a lot of examples, but I haven't found one that involves dealing with nested promises which need to take parameters and then do something conditional based on the value, so I am having difficultly applying them to my situation, mostly because I don't really feel comfortable with asynchronous programming yet. How can I take the mess above and refactor it into something that isn't a nested callback hell?
Maybe playing a little bit with promises, protractor, arguments and bind you could get it quite cleaner.
Then you are using the protractor filter method which needs a boolean to be returned, in order to filter your values. But, from the way you used it, maybe
you were looking for each():
http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.each
I didn't have any chance to test the following code, so it may most probably not work :D
selector = element(by.model("something.someId"));
this.selectorOptions = element.all(by.repeater("repeat in someOptions | orderBy:'name'"));
getSelectedOption = function () {
return this.selector.getText().then(firstText.bind(this));
};
function firstText(text) {
return this.selectorOptions.filter(filterSelector.bind(this, text));
}
function filterSelector(text, option) {
return option.getText().then(optionText.bind(this, text, option));
}
function optionText(text, option, optionText) {
if(optionText === text) {
return option.getAttribute("value").then(someLogic);
}
}
function someLogic(value) {
console.log(value);
// value should be your value
// Some logic here which uses the value to return an pojo representing the selection
// return true or false, filter is still waiting for a boolean...
}
Another version just using arguments without function parameters. Specially follow the arguments which got printed, to see if the order is correct:
selector = element(by.model("something.someId"));
this.selectorOptions = element.all(by.repeater("repeat in someOptions | orderBy:'name'"));
getSelectedOption = function () {
return this.selector.getText().then(firstText.bind(this));
};
function firstText() {
console.log(arguments);
// arguments[0] should be your selectionText
return this.selectorOptions.filter(filterSelector.bind(this, arguments[0]));
}
function filterSelector() {
console.log(arguments);
// arguments[0] should be your previous selectionText
// arguments[1] should be your option
return arguments[1].getText().then(optionText.bind(this, arguments[0], arguments[1]));
}
function optionText() {
console.log(arguments);
// arguments[0] should be your optionText
// arguments[1] should be your selectionText
// arguments[2] should be your option
if(arguments[0] === arguments[1]) {
return arguments[2].getAttribute("value").then(someLogic);
}
}
function someLogic(value) {
console.log(value);
// value should be your value
// Some logic here which uses the value to return an pojo representing the selection
// return true or false, filter is still waiting for a boolean...
}
I am learning protractor and it has thus far been a wild journey because I am also pretty new to Javascript. I learned so far that protractor queues all promises and they can be executed using then().
However, I am now trying to use a filter() on an ElementArrayFinder but it doesn't seem to execute. Only when I preprend it with the return-keyword, the filter get's executed, but then I leave my function and I don't want that.
Can someone help me in understanding this please?
Below my code:
it('Select service', function() {
servicePage.services.filter(function(elem, index) {
return elem.getAttribute('class').then(function(attribute) {
console.log('*****' + attribute);
return attribute === 'service passive';
});
});
servicePage.services.get(0).element(by.tagName('input')).click();
});
When running above, the console log is not performed so I guess the filter function is not being executed. When I do it like below, the filter is executed but then the click() is not performed.
it('Select service', function() {
return servicePage.services.filter(function(elem, index) {
return elem.getAttribute('class').then(function(attribute) {
console.log('*****' + attribute);
return attribute === 'service passive';
});
});
servicePage.services.get(0).element(by.tagName('input')).click();
});
Example3:
it('Select service', function() {
servicePage.services.filter(function(elem, index) {
return elem.getAttribute('class').then(function(attribute) {
console.log('*****' + attribute);
return attribute === 'service passive';
});
}).first().element(by.tagName('input')).click();
});
Thanks in advance!
Regards
You should catch the element that filter function returns and then perform action on it. filter() function returns elements that match the criteria you specify in the function. In your case its returning an element that has a class attribute service passive. If there are more than one elements with same attribute, then you probably have to chain get() function to perform operation on the required element. Here's how -
servicePage.services.filter(function(elem, index) {
return elem.getAttribute('class').then(function(attribute) {
console.log('*****' + attribute);
return attribute === 'service passive';
});
}).element(by.tagName('input')).click(); //if only one element is returning, click on it
OR replace the last line with below line when there are more elements that match the criteria -
}).get(1).element(by.tagName('input')).click(); //click the second element in the array of elements returned
Hope it helps.
I have a javascript that I am using to pull id of a tag . But due to some limitation on a platform where I need to use this I have to make this script under function so I will get the output in return. I am trying but I am failing to get it.
This is the script I have;
var arr2st3 = [].map.call(document.querySelectorAll('article:nth-child(-n+4)'), function(el) {
return el.id.replace(/[^\d]/g, '');
});
This is what I am trying to come up;
function myfun() {
var arr2st3 = []
var arr2st3 = arr2st3.map.call(document.querySelectorAll('article:nth-child(-n+4)'),
function(el) {
return el.id.replace(/[^\d]/g, '');
});
return;
console.log(myfun);
}
This is the test url -> https://jsfiddle.net/v3d0nz9d/
I need to get output in return as ['123456', '7896669', '1147777']
Any help would be highly appreciated.
TIA
[].map is shorthand for Array.prototype.map, so you don't need to store that in a variable, you can just return the return value of your map. Anything after a return statement won't be called, so your console.log is never reached. Also, to log the values returned from your function, you need to call it in your console.log.
function myfun() {
return [].map.call(document.querySelectorAll('article:nth-child(-n+4)'), function(el) {
return el.id.replace(/[^\d]/g, '');
});
}
console.log(myfun());
I've been trying to understand why whenever value of the array I click, it always add the class "foo".
Example: I clicked on London (cities[1], right?) and it added the class foo.
var cities = [
document.getElementById('Paris'),
document.getElementById('London'),
document.getElementById('Berlin')
];
for (var i = 0; i < cities.length; i++) {
cities[i].onclick = test;
function test(){
if(cities[i] === cities[0]) {
el.classList.add("foo");
}
}
}
EDIT: my original answer was incorrect, this updated one is right. addEventListener returns nothing. Instead, you should use some kind of wrapper to add and remove your listeners, again so that you don't waste resources on listeners that you aren't using:
function on (element, eventName, callback) {
element.addEventListener(eventName, callback);
return function unregister () {
element.removeEventListener(callback);
}
}
function test (event) {
if (event.currentTarget===cities[0]) {
event.target.classList.add('foo');
}
}
var listenerRemovers = cities.map(function (city) {
return on(city, 'click', test);
});
Now you can remove any of these listeners by calling the corresponding function in your listenerRemovers array:
listenerRemovers.forEach(function (unRegisterFunc) { unRegisterFunc(); });
ORIGINAL WRONG ANSWER:
For what it's worth, you're probably better off using .map in a case like this, since best practice is to keep a reference to the event listeners so you can cancel them if needed.
function test (event) {
if (event.currentTarget===cities[0]) {
event.target.classList.add('foo');
}
}
var listenerHandlers = cities.map(function (city) {
return city.addEventListener('click', test);
});
This is happening because you are setting the event functions inside a loop. Each function is using the same value of i.
Try to use this instead of trying to cities[i] inside the function.
function test(){
if(this === cities[0]) {
el.classList.add("foo");
}
}
The easiest approach to achieve this functionality is to use jQuery, here is the idea:
In html tags, give those cities a common class, e.g. class="city"
$('.city').click(function(){$('.city').addClass('foo')});
jQuery saves you more time and coding efforts.
The problem is you are trying to assign a function to a DOM attribute. You are not registering a listener but modifying the DOM. If you wish to do it this way, you must assign the onclick as cities[i].onclick = 'test()'
Also, you should move the function test outside of the for loop to look like the following. The problem is the function test is being declared many times, each with a different 'i' value.
for (var i = 0; i < cities.length; i++) {
cities[i].onclick = 'test(this)';
}
function test(el){
if(cities[i] === cities[0]) {
el.classList.add("foo");
}
}
Example:
http://jsfiddle.net/7Cwbn/60/
I'm trying to use array_diff function from PHPJS to check if all of the elements inside selectedFeatures are found inside elem.features, but instead I receive undefined. What gives?
$(markers.houses).each(function(index, elem) {
//first filter by selected features
console.log(array_diff(elem.features, selectedFeatures).length);
if (array_diff(selectedFeatures, elem.features).length == 0) {
if (!markers.houseMarkers[index].visible) {
markers.houseMarkers[index].setVisible(true);
}
}
});
Solution:
Inside array_diff() definition change the retVal to equal [] instead of {}.