pass variable through unobtrusive JavaScript - unobtrusive-javascript

I would like to pass variable from a button to an event handler, but I don't know how what's the right way to do that. Both line x and line y are no good. But I need something like that.
in html head
window.onload = function()
{
var myButton = document.getElementsByTagName("button");
for (var i = 0; i < myButton.length; i++)
{
myButton[i].onclick = function() // <-- line x
{
alert(myButton[i].data1); // <-- line y
}
}
}
in html body
<button type = "button" data1 = "John" data2 = "52">Click Me</button>
<button type = "button" data1 = "Peter" data2 = "26">Click Me</button>
<button type = "button" data1 = "Mary" data2 = "44">Click Me</button>

Take a look at this JSFiddle example I just put together: http://jsfiddle.net/BshLK/1/
The problem with your code sample is that i is undefined by the time your event handler runs as it's only has it's value whilst the loop is running. To correct it, firstly you need to access the element you've called the event on and secondly you need to get use getAttribute() to get the attribute value.

From your onload event I'm guessing you're not using jquery, but if you don't mind jquery I'd take a look at the data() method. You can do things like
$(function(){
$("#button1").data("name", "value"); //your example would pass ("data","abcdefg");
//Click handler.
$("#button1").click(function(o,e){
alert(o.data("name")); // alerts out "value"
}
}
Then you can access that data using a selector to that element.
Link to the documentation

Related

Clickable listitem in Scrollable Material Ui List while using array in list

I am trying to implement List in material-ui. And i am trying to display randomly generated array of elements, they are being displayed with scrollbar list as i want. But i want to select that particular List Item which is the issue as i m unable to select it, even by using on click. So can anyone help me in this.
Here is my code:
var MuiListElement = React.createClass(
{
handleClick() {
console.log("secondList clicked")
},
render()
{
let faker = require('faker')
let myItems = []
for(let i = 0; i < 5000; i++)
{
let name = faker.Name.findName()
myItems.push(<ListItem onClick={this.handleClick()} key={i.toString()}>{name}</ListItem>)
}
return(
<div style={{width:'400px'}}>
<Paper style={{maxHeight: 200, overflow: 'auto'}}>
<List selectable='true'>
{myItems}
</List>
</Paper>
</div>
)
}
}
)
this.handleClick() calls handleClick function during your render, you should call it when the user clicks the list item. You wan't to pass the function to onClick, not call the function.
myItems.push(
<ListItem
onClick={this.handleClick} //pass function, don't call function
key={i}> //note: you can pass key as number
{name}
</ListItem>)
Now let me predict the future, you would like to know what item was clicked. You can use bind.
myItems.push(
<ListItem
onClick={this.handleClick.bind(this, i)} //bind returns a function
key={i}>
{name}
</ListItem>)
now you know what was passed
handleClick(i) {
console.log("secondList clicked", i)
},
However, every time you render, you are creating a new function and will slightly degrade performance.
See this discussion,
React js onClick can't pass value to method
Let me know if you don't understand.

Class prefix as selector for each function

I am able to do this using an ID prefix as the selector, but I need to be able to do it with classes instead. It's an each function for opening up different modal windows on the same page. I need to avoid using ID names because I have some modal windows that will have multiple links on the same page, and when using IDs, only the first link will work.
So here's the function as it works with IDs:
$('div[id^=ssfamodal-help-]').each(function() {
var sfx = this.id,
mdl = $(this),
lnk = $('.link-' + sfx),
cls = $('.ssfamodal-close'),
con = $('.ssfamodal-content');
lnk.click(function(){
mdl.show();
});
cls.click(function(){
mdl.hide();
});
mdl.click(function() {
mdl.hide();
});
con.click(function() {
return false;
});
});
and I'm trying to change it to classes instead, like:
$('div[class^=ssfamodal-help-]').each(function() {
var sfx = this.attr('class'),
etc.
But I cannot get it to work without using IDs. Is it possible?
EDIT Fixed error with semi-colon at end of Vars, and updated Fiddle with the fix. Still not working though.
Here's a Fiddle
** UPDATE **
To be clearer, I need to be able to refer to the same modal more than once on the same page. E.g.:
MODAL 1
MODAL 2
MODAL 3
MODAL 4
LINK TO MODAL 1
LINK TO MODAL 2
LINK TO MODAL 3
LINK TO MODAL 4
OTHER STUFF
LINK TO MODAL 1
LINK TO MODAL 4
LINK TO MODAL 3
OTHER STUFF
LINK TO MODAL 2
ETC.
When using classes get rid of the ID habit :
className1, className2, className3 ... etc
simply use
className
HTML:
<div class="ssfamodal-help-base ssfamodal-backdrop">
<div id="help-content" class="ssfamodal-content">
<span class="ssfamodal-close">[x]</span>
Howdy
</div>
</div>
<div class="ssfamodal-help-base ssfamodal-backdrop">
<div id="help-content" class="ssfamodal-content">
<span class="ssfamodal-close">[x]</span>
Howdy Ho
</div>
</div>
<span class="link-ssfamodal-help-base">One</span>
<span class="link-ssfamodal-help-base">Two</span>
LIVE DEMO
var $btn = $('.link-ssfamodal-help-base'),
$mod = $('.ssfamodal-help-base'),
$X = $('.ssfamodal-close');
$btn.click(function(i) {
var i = $('[class^="link-"]').index(this); // all .link-** but get the index of this!
// Why that?! cause if you only do:
// var i = $('.link-ssfamodal-help-base').index();
// you'll get // 2
// cause that element, inside a parent is the 3rd element
// but retargeting it's index using $('className').index(this);
// you'll get the correct index for that class name!
$('.ssfamodal-help-base').eq(i).show() // Show the referenced element by .eq()
.siblings('.ssfamodal-help-base').hide(); // hide all other elements (with same class)
});
$X.click(function(){
$(this).closest('.ssfamodal-help-base').hide();
});
From the DOCS:
http://api.jquery.com/eq/
http://api.jquery.com/index/
http://api.jquery.com/closest/
Here I created a quite basic example on how you can create a jQuery plugin of your own to handle modals: http://jsbin.com/ulUPIje/1/edit
feel free to use and abuse.
The problem is that class attributes can consist of many classes, rather than IDs which only have one value. One solution, which isn't exactly clean, but seems to work is the following.
$('div').filter(function () {
var classes = $(this).attr('class').split(/\s+/);
for (var i = 0; i < classes.length; i++)
if (classes[i].indexOf('ssfamodal-help-') == 0)
return true;
return false;
}).each(function() {
// code
});
jsFiddle
Or, equivalently
$('div').filter(function () {
return $(this).attr('class').split(/\s+/).some(function (e) {
return e.indexOf('ssfamodal-help-') == 0;
});
}).each(function() {
// code
});
jsFiddle
If there is one-to-one relationship between the modal helps and the modal links which it appears there is...can simplfy needing to match class values by using indexing.
For this reason you don't need unique class names, rather they just overcomplicate things. Following assumes classes stay unique however
var $helps=$('div[id^=ssfamodal-help-]');
var $help_links=$('div[id^=link-ssfamodal-help-]');
$help_links.click(function(){
var linkIndex= $help_links.index(this);
$helps.hide().eq( linkIndex ).show();
});
/* not sure if this is what's wanted, but appeared original code had it*/
$helps.click(function(){
$(this).hide()
})
/* close buttons using traverse*/
$('.ssfamodal-close').click(function(){
$(this).closest('div[id^=ssfamodal-help-]' ).hide();
});
Also believe that this code is a little more readable than original apporach
DEMO
Can you try this,
$('div[class^=ssfamodal-help-]').each(function() {
var sfx = $(this).attr('class');
console.log(sfx);
/*console log:
ssfamodal-help-base ssfamodal-backdrop
ssfamodal-help-base2 ssfamodal-backdrop
*/
});
Demo: http://jsfiddle.net/xAssR/51/
why don't you write like
$('div.classname').each(function() {
// you can write your desired code here
var sfx = this.attr('class');
var aa= this.attr('id');
});
or
$('.classname').each(function() {
// you can write your desired code here
var sfx = this.attr('class');
var aa= this.attr('id');
});
where classname is the name of the class used for the div in html
Thanks.

Mvvm with knockout : array binding and changing inner objects state

I have an array in my View Model. Items of this array are objects of Person that has two properties. when I bind this to a template it's okay. but when I change the state of one of the properties it does not reflect in UI.
what did I do wrong ?
<script type="text/html" id="person-template">
<p>Name: <span data-bind="text: name"></span></p>
<p>
Is On Facebook ?
<input type="checkbox" data-bind="checked: IsOnFacebook" />
</p>
</script>
<script type="text/javascript">
var ppl = [
{ name: 'Pouyan', IsOnFacebook: ko.observable(true) },
{ name: 'Reza', IsOnFacebook: ko.observable(false) }
];
function MyViewModel() {
this.people = ko.observableArray(ppl),
this.toggle = function () {
for (var i = 0; i < ppl.length; i++) {
ppl[i].IsOnFacebook = false;
}
}
}
ko.applyBindings(new MyViewModel());
</script>
when I press the button I want to make changes in People.IsOnFacebook property. the changes will be made successfully but the UI does not show.
You should call it like a function. Like:
ppl[i].IsOnFacebook(false);
This because the ko.observable() returns a function. It's not a property you call anymore but a function call. So in the background they will update your UI. To retreive a property that is observable. You should also use the function call.
Please see this tutorial: http://learn.knockoutjs.com/#/?tutorial=intro

Mootools stop form submit method

I don't want to use an <input type=submit /> button to submit a form and I am instead using an <a> element. This is due to styling requirements. So I have this code:
myButton.addEvent('click', function() {
document.id('myForm').submit();
});
However, I have also written a class that improves and implements the placeholder attribute on inputs and textareas:
var FDPlaceholderText = new Class({
Implements: Events,
initialize: function() {
var _self = this;
var forms = document.getElements('form');
forms.each(function(form) { // All forms
var performInit = false;
var i = 0;
var ph = [];
form.getElements('input, textarea').each(function(el) { // Get form inputs and textareas
if (el.getProperty('placeholder') != null) { // Check for placeholder attribute
performInit = true;
ph[i] = _self.initPlaceholder(el); // Assign the placeholder replacement to the elements
}
i ++;
});
if (performInit) {
_self.clearOnSubmit(form, ph);
}
});
},
clearOnSubmit: function(form, ph) {
form.addEvent('submit', function(e) {
ph.each(function(el) {
if (el.value == el.defaultValue) {
el.value = '';
}
});
});
},
initPlaceholder: function(el) {
el.defaultValue = el.getProperty('placeholder');
el.value = el.getProperty('placeholder');
el.addEvents({
'focus': function() {
if (el.value == el.defaultValue) el.value = '';
},
'blur': function() {
if(el.value.clean() == ''){
el.value = el.defaultValue;
}
}
});
return el;
}
});
window.addEvent('domready', function() {
new FDPlaceholderText();
});
The above class works great if a form is submitted using an actual <input type=submit /> button: it listens for a submit and clears the inputs values if they are still the default ones therefore validating that they are essentially empty.
However, it seems that because I am submitting one of my forms by listening to a click event on an <a> tag the form.addEvent('submit', function(e) { isn't getting fired.
Any help is appreciated.
well you can change the click handler to fireEvent() instead of call the .submit() directly:
myButton.addEvent('click', function() {
document.id('myForm').fireEvent('submit');
});
keep in mind a couple of things (or more).
placeholder values to elements that lack placeholder= attribute is pointless
if you detect placeholder support, do so once and not on every element, it won't change suddenly midway through the loop. you can go something like var supportsPlaceholder = !!('placeholder' in document.createElement('input')); - remember, there is no need to do anything if the browser supports it and currently, near enough 60% do.
you can otherwise do !supportsPlaceholder && el.get('placeholder') && self.initPlaceholder(el); - which avoids checking attributes when no need
when the form is being submitted you really need to clear placeholder= values in older browser or validation for 'required' etc will fail. if validation still fails, you have to reinstate the placeholder, so you need a more flexible event pattern
avoid using direct references to object properties like el.value - use the accessors like el.get('value') instead (for 1.12 it's getProperty)
for more complex examples of how to deal with this in mootools, see my repo here: https://github.com/DimitarChristoff/mooPlaceholder
This is because the submit() method is not from MooTools but a native one.
Maybe you can use a <button type="submit"> for your styling requirements instead.

getting class attr in jquery

I have some divs that are generated dynamically with content. I add the content id to the class for the div like so:
<div class="div-1"></div>
<div class="div-3"></div>
<div class="div-6"></div>
<div class="div-8"></div>
How do I select the id for a div because I need it as a param to send via ajax. e.g. I need to get the 1 when I click on the 1st div, 3 when I click on 2nd and so on
var id = $(this).attr('class').replace('div-', '');
Or even simple
var id = this.className.replace('div-', '');
Where this points to the dom element you click on inside the click handler.
//Here instead of document it is better to specify a parent container of all divs
$(document).on('click', '[class^="div-"]', function(){
var id = this.className.replace('div-', '');
});
Try this, and remember changing "div" for your selector:
$(document).on("click", "div", function() {
var class_elem = $(this).attr("class").split("-");
var n = class_elem[1]; // This is your number
});
The correct jQuery syntax is:
$("div").click( function() {
var id = $(this).attr('class').replace('div-', '');
});