I am somewhat new to jQuery and am hoping to get a little help on this problem I have.
Heres what I am trying to do:
I need the ability to fire off a notification when a user selects an option from a select box. All the select boxes on the page share the same id and name, as well as live under div classes with the same name. This part is working, however I will have multiple select boxes on the page. When I make a selection for one, it fires off the notification to all instances instead of just the selected one.
How do only get the notification to fire on the selected instance?
Here is the JS so far:
$("select[name=regStatus]").change(function () {
var str = "";
var text = $(this).find("option:selected").text();
str += " Status changed to: " + $(this).find("option:selected").text();
$(".responseMsg").text(str).fadeIn(500);
$(".responseMsg").delay(2000).fadeOut(1000);
return false;
});
AND the html structure (this code will be repeated on the page several times):
<div class="dash-hdr-extras plain">
<div class="responseMsg"></div>
<select id="regStatusSelect" name="regStatus">
<option value="0">Example1</option>
<option value="blah">Blah</option>
<option value="blah2">Blah 2</option>
</select>
</div>
Any help on this would be greatly appreciated, as I am still learning!
$("select[name=regStatus]").change(function () {
//...Your code...
$(this).parent().find(".responseMsg").text(str).fadeIn(500);
//...Rest of your code...
});
This gets the parent of the element that fired the change event, and then finds the children of that element matching the selector.
The reason it was writing your message to all .responseMsg elements, is that using $(".responseMsg") simply selects all matching elements in the DOM, and applies whatever follows to the entire set.
Another option, if you are sure the structure of your HTML is not going to change, is to use the prev method, which gets the previous sibling of the current element. With the code in your question, that's fine, but if it changes this might not work:
$(this).prev().text(str).fadeIn(500);
On a separate note, you mention in your question that all select elements have the same ID. That's invalid HTML and will cause you no end of problems. Every ID in a document needs to be unique.
Try this
$("select[name=regStatus]").change(function () {
var str = "";
var text = $(this).find("option:selected").text();
str += " Status changed to: " + $(this).find("option:selected").text();
$(this).closest("div.dash-hdr-extras").find("div.responseMsg").text(str).fadeIn(500)
.delay(2000).fadeOut(1000);
return false;
});
Also, like james said, Ids should not be repeated. To use the same function on many elements, do this:
$("#select1")
.add('#select2')
.add('#select3')
.add('#select4')
.add('#select5')
.change(function () {
});
keep the Ids unique...
Related
I'm trying to use bootstraptoggle in one of my pages. The initial state is off / disabled.
The page loads several boolean values and stores them as hidden text. Then I have a script which looks them up via their IDs. Upon that hidden text it should toggle the slider.
I was able to get the hidden text and make the conditional check but I'm not able to toggle the slider for some reason.
Here is my code:
$(document).ready(function () {
var flags = [];
var userID = '',
toggleSlider = '';
flags = document.querySelectorAll('*[id^="activeFlag_"]');
flags.forEach(function (flag) {
userID = flag.id.split('_')[1];
// This is where i search for the hidden text
if (flag.firstChild.data == 'True') {
// Nothing works here.
$('#activeToggle_' + userID).bootstrapToggle('toggle');
}
});
});
And this is the html code that I need to work with:
<p id="activeFlag_#user1">#item.activeFlag</p>
<div class="checkbox">
<label>
<input id="activeToggle_user1" type="checkbox" data-toggle="toggle" data-on="Enabled" data-off="Disabled">
</label>
</div>
Your code is too opaque without any data example.
However one thing could be a cause of its problem:
if (flag.firstChild.data == 'True') {
Try to replace it with:
if (flag.firstElementChild.data == 'True') {
Here you could find explanation:
The firstChild property returns the first child node of the specified node, as a Node object.
The difference between this property and firstElementChild, is that firstChild returns the first child node as an element node, a text node or a comment node (depending on which one's first), while firstElementChild returns the first child node as an element node (ignores text and comment nodes).
Note: Whitespace inside elements is considered as text, and text is considered as nodes (See "More Examples").
Update after example code was added
For the example code you provided, you should change the split argument:
userID = flag.id.split('_')[1];
to:
userID = flag.id.split('_#')[1];
Thanks to twain for initial jsfiddle. I have updated it accordingly: jsfiddle
I guess the problem is, that the following part does not use the correct id for the toggle $('#activeToggle_' + userID).bootstrapToggle('toggle');
Your html ID is activeToggle_user1, but the js part above will probably resolve to #activeToggle_1. So the text user is missing here.
I created a working fiddle here: https://jsfiddle.net/pbcrh5d2/
Ok, for some reason asp.net and javascript have a problem with coping together. I used asp.net to provide javascript to build the strings.
So I switched to the raw id that is used in the table.
I want to select a button with casperjs, but my issue is that the button has changing IDsand classes. I can only "identify" the button, based on the text of a span 2 levels done:
<button class="changes-always" id="changes-always-too">
<div class="changes-always2">
<span class="changes-always3">Same text</span>
</div>
</button>
With jQuery I can select the button, by first selecting the span, because it always has the same content.
var span = $('span:contains("Same text")');
var button = span.parent().parent() // there is probably a nice way to do this
I got jQuery loaded by casperjs by including it as clientScripts, my issue is how to correctly get it working with the evaluate(function() as well as use the variables as selectors with casperjs (if that's even possible)
This is how far I got, but then I ran into problems with object and string issues.
casper.then(function() {
var items = this.evaluate(function () {
return $('span:contains("Some text")');
});
console.log(items);
});
Would be great, if someone could point me in the right direction, how to use jQuery as a selector and then let casperjs use it. Thanks many times in advance!
You can also use clickLabel() if the text is unique.
casper.clickLabel("Some text");
This should work for buttons, too.
Another option and still not with jquery should be getting the id's by text and if there are sometimes the same text, grab them out by the index:
...
var x = require('casper').selectXPath;
var buttonIDs;
// get button ID's with specific text by getElementsAttribute with xPath selector
buttonIDs = casper.getElementsAttribute(x("//button[contains(text(),'Some specific text')]"), 'id');
casper.then(function() {
casper.echo(buttonIDs);
});
casper.then(function() {
casper.click("button[id='" + buttonIDs[0] + "']");
});
...
I have an on-line store that has a product page. The page has two select boxes to choose from and will filter results based on those two options.
If I choose criteria A + B from the select boxes, the page filters through the products to show products with that criteria. However when this event happens, the page scrolls to the top of the page. This is especially annoying on mobile as the select boxes are not at the top of the page.
How can I add either a javascript event to scroll to a specific div (for example #ProductList) when the selection is made.
Or maybe an onload event that adds the #ProductList to the end of the url.
I have found examples to scroll to a div id based on the id selected. But I need something simpler that always scrolls to the same div #ProductList when the select boxes are clicked.
This Example works for id selected but i need a general one that scrolls to one specific div id
var select = document.getElementById('test');
select.onchange = function(){
var id = this.getElementsByTagName('option')[this.selectedIndex].value,
el = document.getElementById(id),
top = el.offsetTop;
window.scrollTo(0,top);
};
Any help is hugely appreciated!!!!
Frank
You can use URL fragments to jump to the required page element. See the snippet below:
var select = document.getElementById('test');
select.onchange = function(){
var id = this.getElementsByTagName('option')[this.selectedIndex].value;
var link = window.location.href;
// If URL already has a fragment, remove it
if (link.indexOf('#') != -1)
link = link.substring(0, link.indexOf('#'));
// Add URL fragment with id of the div you want to jump to
window.location.href = link + '#' + id;
};
Just write
var id = 'YOUR ID HERE',
instead of
var id = this.getElementsByTagName('option')[this.selectedIndex].value,
what i would do is
$("#test").change(function(){
var val=$(this).val();
var divtext=""+$("#"+val+" p").html();// this is div content
});
I've figured it out!
Thanks for the different perspectives guys! Really helped me to stumble upon the answer!
You can delete/archive this post if needed. First time here so not sure on the protocol!
Thanks again
Frank
I have a DropDownList where onChange sets the content of the TextArea which is my CKEditor control.
When the editor is not in use I run this bit of code for onChange:
$(".setBody").change(function() {
//
var className = "." + $(this).attr("sExternalId");
var text = $(this).val();
//
$(className).val(text);
});
I'm not very experienced with Javascript/JQuery and I just can't figure out how to perform the same using CKEditor's setData() function. This is what I've tried:
$(".setCKBody").change(function() {
//
var className = "." + $(this).attr("sExternalId");
var text = $(this).val();
//
var editor = $(className).ckeditorGet();
editor.setData(text, function() {
alert("The content was set");
});
});
$(".setCKBody").change(function() {
//
var className = "." + $(this).attr("sExternalId");
var text = $(this).val();
//
CKEDITOR.instances[$(className)].setData(text, function() {
alert("The content was set");
});
});
Am I close? I think one of the main limitations is that I have multiple editor controls with the same id and name, only the class can tell them apart which is why I'm using that with the JQuery. I've tried working through some examples online, but I'm not sure how to apply them to this scenario - that's probably my inexperience coming through there...
Thanks.
EDIT
This is how my textarea and dropdownlist appears in view source:
<textarea class="editArea M3" cols="20" id="Body" name="Body" rows="5">
*some text*
</textarea>
<select class="setCKBody" id="Templates" name="Templates" sExternalId="M3">
<option value="some value">Option 1</option>
<option value="some value">Option 2</option>
</select>
The onChange event above is triggered from the dropDownList changing and is linked to the textArea via the "sExternalId" attribute. I realised I used "id" as the attribute name in the example above which was in error, so I changed that.
I use this to set it as a CKEditor control:
<script>CKEDITOR.replaceAll('editArea');</script>
I have between 2 to 6 textarea controls on the same page, created with razor like this:
#Html.TextAreaFor(m => m.Body, new { #class = "span12 editArea " + Model.ExternalId, rows = 5 })
They are contained within a partial view that is used like this:
#foreach (MailTemplateModel oTemplate in Model.Templates)
{
#Html.Partial("_MailPartial", oTemplate)
}
This is why each text area has "Body" set as the id and name. I think this is the heart of the problem, with there being multiple elements with the same id and name CKEditor is not able to select the correct one. I've tried to do CKEDITOR.instances["className"] but that was undefined, whereas doing CKEDITOR.instances.Body did work, but would only ever return the same value.
I'm going to restructure the way the page is created to avoid this, hopefully my issues will be solved at the same time.
Here's a few pointers.
Use class="foo" if you have many things that you refer to as a group, like like here it looks like you would have many setCKBody elements you listen to for change events.
Use id="foo" if you have one single specific thing.
Using the same id and class for one element usually is not the right thing to do.
CKEDITOR.instances[xxx] <-- xxx should be a string, not a jquery object - so CKEDITOR.instances[className] might work better (I can't say not having seen your HTML).
It would help if we saw your HTML; textarea definitions and setCKBody definitions. Do you have many ckeditors and many setCKBody elements?
My original approach to this scenario was all wrong, I had a model that contained multiple mail templates and so I rendered each one via a partial view within the same page so that the user could click to edit any one of them and the details would appear in a modal popup - within the same window. What I wanted to avoid was forcing the user to navigate to another window to edit a mail template, but this lead to multiple elements having the same id and name attributes which prevented me from accessing them correctly.
I've now added a list box where the user can select a template to edit, the selected template is rendered underneath and so avoids the multiple name and id issue. Now I know there is only ever 1 CKEditor control so I can access it in my js like this:
var editor = CKEDITOR.instances.SelectedTemplate_Body;
SelectedTemplate_Body is the name and id of the element I made into a CKEditor control. The onChange function I wrote for the dropdownlist is now written like this:
$(document).ready(function() {
//
$(".setBody").change(function() {
//
var templateId = $(this).val();
//
$.ajax({
type: "GET",
url: msHost + "MailTemplates/UpdateBody",
data: { "templateId": templateId },
cache: false,
dataType: "text",
success: function (data) {
CKEDITOR.instances.SelectedTemplate_Body.setData(data);
}
})
});
});
The tempalteId attribute is the value associated to the dropdownlist selection, this lets me know which template to use for setting the content of my editor control.
MailTemplates/UpdateBody points to a public method in my MailTemplates controller which runs a search on available mail templates and matches against the template Id passed in, the method then returns the body of the template as a string.
public string UpdateBody(string tempalteId)
{
TemplateQuery oQuery;
//
oQuery = new TemplateQuery();
oQuery.Execute();
foreach (MailTemplate oTemplate in oQuery.Results)
if (oTemplate.Id.Equals(templateId))
return oTemplate.Body;
//
return string.Empty;
}
This line replaces the contents of the CKEditor control with the response from the controller method.
CKEDITOR.instances.SelectedTemplate_Body.setData(data);
Thanks #Nenotlep for trying to help out, you gave me a few things to think about there.
Here's some low-hanging fruit for those more comfortable with Javascript than I...
I want to improve a Moodle plugin's admin UI. (Moodle is a PHP-based web app). What I need to do is take what is currently a text box, with semi-colon delimited entries and replace that with a editable list.
The HTML elements I would use is a select list, a text input field and another hidden textfield. I guess a couple of submit buttons too, one for adding, and the other for removing of entries.
The behaviour would be:
Entries can be added to the select list from the visible textbox upon some kind of submit (this cannot reload the page).
The hidden textbox would contain all the entries from the select list, just semi-colon delimited
There's a function to remove entries from the select list that also does not reload the page.
The hidden textbox is updated with add/remove actions
This seems to me like something that's easy enough. Though I'm having a hard time finding a close enough example to rip off.
This sample code is as close as I've found thus far. There's got to be some good examples of precisely this sort of thing out there. Any decent pointers will be rewarded with + votes.
What you want to do is use JavaScript and manipulate with the DOM of the webpage. Basically, the HTML of a webpage is parsed and rendered by the browser into a tree of elements. Each HTML tag like <select> is an element in the tree. You use JavaScript to interact with this tree by performing operations like removing elements from this tree or adding elements to this tree. (Note that preforming operations on the tree will not refresh the page.)
The standardized API to do these sorts of manipulation in JavaScript is known as the DOM. However, many people, myself included, think that this API is very clunky and not nearly expressive enough. Doing even trivial things require tons of lines of code. For this reason, many developers do not use the DOM directly instead using more powerful libraries, such as jQuery, to make their lives easier.
Below is an example of some HTML + JavaScript that I think mimics most of your requirements. Ideally for learning purposes, this would be written purely using the standard W3C DOM API, but since your problem is not that trivial, I resorted to using jQuery instead.
The HTML:
<select id="list" multiple="multiple"></select>
<input id="removeButton" type="button" value="Remove"></input>
<div>
<input id="optionAdder" type="text"></input>
<input id="addButton" type="button" value="Add"></input>
</div>
<br>
<input id="clearButton" type="button" value="Clear All"></input>
<div>Not So Hidden: <input id="hidden" type="text"></input></div>
The JavaScript:
// Uses jQuery to define an on document ready call back function
$(function(){
// The code in this function runs when the page is loaded
var options = []; // contains all the options
// add new option to drop-down
var addOption = function(optText) {
// Create new option element and add it to the <select> tag
$('<option></option>')
.attr('value', optText).text(optText)
.appendTo( $('#list') );
};
// writes the names of all the options in the "hidden" text box
var fillHidden = function() {
$('#hidden').val('');
var hiddenText = "";
for(var i=0; i< options.length; i++) {
if(hiddenText) {
hiddenText += "; ";
}
hiddenText += options[i];
}
$('#hidden').val(hiddenText);
}
// Bind the click event of the "Add" button to add an option on click
$('#addButton')
.click(function(){
var optText = $('#optionAdder').val();
if(optText) {
addOption(optText);
}
$('#optionAdder').val('');
options.push(optText);
fillHidden();
});
// Bind the click event of the "Remove" button to remove the selected options on click
$('#removeButton')
.click(function(){
$('#list option:selected').each(function(){
var optIndex = $.inArray($(this).val(), options);
if(optIndex > -1) {
options.splice(optIndex, 1);
$(this).remove();
}
fillHidden();
});
});
// Bind the click event of the "Clear" button to clear all options on click
$('#clearButton')
.click(function(){
$('#list').children().remove();
options = [];
fillHidden();
});
});
Here is a jsfiddle demonstrating the code