Showing an element with a common ID, hiding others - javascript

I'm attempting to create a system that, when one element is selected, shows an element of the same ID whilst hiding the previous without hiding all instances of that ID (i.e. it is only hidden if a certain class is present).
The first part (making an element 'active' and setting the ID variable) works fine, but I can't seem to get the secondary element to stop being set using the '.hidden' class.
The code I'm using for this part is
function showSelect() {
select = $(".active").attr('id');
$(".items").addClass("hidden");
$("#"+select).removeClass("hidden");
}
I've tried using $(select).remove... on the fourth line, as well as what is currently present, but to no avail.
The rest of the code can be found on http://jsfiddle.net/ActualRealJamz/2JZA6/
I'm not sure what I'm doing wrong here, and JSHint reports no syntax error of any kind - so in that there must be an error to my method.
If this happens to be of any use, Chrome reports an 'Unexpected identifier' on the line $(".items").addClass("hidden");.
Any help in this matter is most appreciated.

As Barmar pointed out in the comments, that fundamentally cannot work because you cannot have the same id on more than one element. If you do, the document is invalid and the browser is free to ignore the id values. (In practice, they typically act as though only the first element in the document with a given id value has that id, ignoring subsequent ones.)
You seem to be using the class items on the relevant elements, so it's straight-forward to do what you're looking to do. Assuming showSelect is attached to the relevant elements as a click handler, within showSelect, this will be the specific element that was clicked. So:
// Hooking it up
$(".items").click(showSelect);
// The function
function showSelect() {
$(".items").not(this).addClass("hidden");
$(this).removeClass("hidden");
}
No ids required at all.

Related

Cypress - Waiting for an element which has same attributes with other elements already existed

This problem that I'm facing is common for me and I want to learn for about best practices.
My problem is:
I have to wait a text which has an attribute of ".title" class and the text involves the statement of: "Hello". Before triggering this element to come to surface, we have an element already have attributes of ".title" which have a text of "StatementX" as well (At the end of the process, I have 2 ".title" class items on screen).
When I tried to wait for the element "Hello", I write:
`cy.get('.title').contains('Hello').should('be.visible')
`
Since "StatementX" is already on the screen, Cypress finds ".title" class and does not check "contains" part. What is the best practice to handle such cases?
Thank you so much
If you move the class .title into command .contains() it will focus solely on the element you wish to test, i.e two criteria will be tested in one command call and it will find the specific element.
cy.contains('.title', 'Hello').should('be.visible')
If you don't have any difference at all in those elements you will have a return of an array of elements.
In that part .eq(NUMBER OF THE ARRAY) you can validate the option that you want.
Also you can use XPATH for those cases. Not recommended since it's volatile but since is old stuff that is not changed it should have an higher change of stability.

Triggering change on input

I have written some code that changes an input quantity on a magento 1.9 ecommerce website.
jQuery("input.qty").val("10");
The problem is the javascript that triggers the total to update doesn't fire. I have found the code responsible and it looks like this:
(function() {
var qtyFields = $('super-product-list').select('input.qty');
qtyFields.each(function(el) {
el.observe("change", updateGroupedPrice);
});
Event.observe(window, "load", updateGroupedPrice);
function updateGroupedPrice() {
//do stuff
}
})();
I think this is using prototype.js but I tried to isolate it in a codepen but couldn't get it working.
I have tried to trigger the change event like so:
jQuery("input.qty").trigger("change")
But it does not work. I also ran through a load of other events but in the dev tools it shows the code listening on "change".
Does anyone know why I can't trigger the change?
Since the page is using Prototype.js, you ought to keep using that to trigger your change. If you introduce jQuery into this, you're a) loading another complete duplicate of what Prototype already does, and b) asking for a lot of trouble isolating the fact that $() is a method in both libraries.
Your jQuery is a little fishy to me, too. You're setting the value of one picker (I imagine) and yet you are addressing it with a classname, so potentially there is more than one select.qty in the page, and all of them will change to value 10, firing off (potentially) multiple callback functions.
The Prototype code you see here is setting up a "listener" for changes on what you would address in jQuery as$(#super-product-list input.qty) inputs.
jQuery always treats $() as returning an array of objects, and thus all of its methods act on the array, even if it only contains one member. Prototype has two different methods for accessing elements in the DOM: $('some_id'), which always returns one element (or none, if no match), and $$('some css selector'), which always returns an array (of zero or more matching elements). You would write (or use native) callback methods differently, depending on which accessor you used to gather the element(s).
If you want to change one of these inputs, you will need to isolate it before you set its value.
Let's say there are three select pickers with the classname qty in your #super-product-list element. You want to change the third one to 10:
$('super-product-list').select('input.qty').last().setValue('10');
Or, much smarter than this, you add an ID to the third one, and then your code is much shorter:
$('quantity_3').setValue('10');
In either case, this will send the "change" event from your select, and the updateGroupedPrice method will observe that and do whatever you have coded it to do.
You won't need to (and should not ever) trigger the change event -- that's a "native" event, and the browser owns it. jQuery's trigger() (which is fire() in Prototype, is used exclusively for "synthetic events", like you see in Bootstrap: show.bs.modal, hide.bs.modal, etc. You can spot these by the punctuation in their names; usually dots or colons to namespace the events and avoid collisions with other code.
Finally, if you really, really, really wanted to change every single #super-product-list select.qty element on the whole page to '10', you would do this in Prototype.js:
$$('#super-product-list select.qty').invoke('setValue', 10);

multiple elements with ng-if and always only 1 of them is shown, can they share the same id?

As in title. I want to have 2 elements with ng-if and the same id, only 1 of them is shown at the same time. I am wondering if they can have the same id, since ng-if will remove 1 of the elements, so there will be only 1 element with that id.
I mean not only if it can be done, but also if it's a good way of doing things.
Here is the code sample of what I have in mind (it's been simplified):
<span id="elementType" ng-if="vm.type === 1">type1</span>
<span id="elementType" ng-if="vm.type === 2">type2</span>
Let's say that vm.type can only have values of 1 and 2.
Edit: Using a class instead of id is not possible for me. I am just wondering if I can use a single id for every element, or do all of them need to have separate id.
Edit2: I cannot use a class and need ids because I make these changes for tests, which rely on testing by ids. I cannot change that, so using class is not an option for me and is not an answer to my question at all.
Edit3: I am also absolutely sure that there will always be only one of the elements with ng-if displayed. I only need it for displaying element type, and there will always be exactly one type. If by any chance, the requirements change, it would already require massive changes, compared to which, changing things like displaying of the element type is not a problem at all.
You can see my fiddle that is based on your code.
Setting same 'id' on different element
$scope.changeType = function (){
if($scope.type===1){
$scope.type = 2;
} else if($scope.type===2){
$scope.type = 1;
}
};
This is handled by using 'ng-click', so it might be able to far from perfect for your purpose.
And if you use 'ng-if', you can set same 'ID' on different elements.
But using same id is not good because anybody doesn't know when errors occur from that.
And welcome every feedback. :)
To answer your question, Yes.
In the setup you outlined, it's ok since only one element is present in the DOM at a time.
I ran into the same situation, due to existing restrictions. After looking at the id attribute according to W3, as long as there is only one element with the ID in the DOM tree, it should be ok. ng-if removes the element from the DOM so it should be acceptable.
NOTE: Some of the folks in the comments made some very good point. It is generally bad practice to have multiple elements with the same ID, as noted in the comments. Read comments for more info and to get the context.

Remove message, Framework7

I can't seem to remove just one message using the JS framework, Framework7. There is a "myMessages.removeMessage(message);" where message is "HTMLElement or string (with CSS Selector) of message element to remove.". But I cant get this to work on just 1 message. Either all gets removed or none. Ive inspected the elements and they all seem to be the same (see screenshot). Removing all can be done with e.g.
myMessages.removeMessage(".message-first");
Adding e.g. ".message-received" removes all received messages and so on. Cant find anything that separates between the very last message and all others.
Anyone that has any idea how to remove the last message (or a specific message) with Framework7?
Use Dom library from Framework7 (doc), to delete the last element who matched with ".message-first", simply do a $$.find(), take last item and delete it with .delete().

jquery ".prop()" does not work before appending to body

I used jquery to create an initially blank select element. I tried this:
$('<select><option>1<option>2</select>').prop('selectedIndex', -1).appendTo(document.body);
This successfully creates a select box, but it is not blank. Through experimenting, i found out that this works:
var $new = $('<select><option>1<option>2</select>').appendTo(document.body);
$new.prop('selectedIndex', -1);
What is different between those two is that when theselectedIndex property is set: before or after it is appended to the body. Can you explain reason beneath this?
Here is a JSFiddle: http://jsfiddle.net/R9auG/
It just looks to me like the $.prop() function must run after the item is appended to the body. Here's an example using your first code: http://jsfiddle.net/jakelauer/R9auG/311/
And the code itself:
$('<select><option>1</option><option>2</option></select>')
.appendTo(document.body)
.prop('selectedIndex', -1);
PS - You are not closing your <option> tags in the jQuery. The browser is smart and is fixing this for you, but it could cause big problems if you don't close them like I did in my example.
If there are no options with the selected attribute when the browser first renders the element, it'll choose the first one.
I thought this was required by the spec, but it turns out that this was undefined in HTML 4.01 and I can't find anything about it at all in the current spec.
There is this, from the HTML 4.01 spec:
Note. Since existing implementations handle this case differently, the current specification differs from RFC 1866 ([RFC1866] section 8.1.3), which states:
The initial state has the first option selected, unless a SELECTED attribute is present on any of the elements.
Since user agent behavior differs, authors should ensure that each menu includes a default pre-selected OPTION.
In any case, that does seem to be how it's still handled.
In your first example, the browser doesn't understand the selectedIndex property yet because the DOM object doesn't exist until after the select element is rendered. That property is created when the browser creates the object. You can't change the property of an object that doesn't exist yet.
This is confusing... we're dealing with two separate types of objects: a jQuery object and a DOM object.
In your second example, the browser renders the select element and creates an object with a selectedIndex property which you immediately change to say that nothing (-1) is selected.
You might find the "placeholder label option" useful if you read about it in the details of the select element specification.

Categories

Resources