Howler.js - referencing and triggering files from an array/for-loop - javascript

I'm trying to use an array and for-loop to index and name some Howls and Howl trigger buttons.
I've referenced this question for what I'm trying to achieve: Howler - Random sound
The difference with mine is that it's without the random aspect plus I've added some method calls.
I'm adding the buttons used to trigger the Howls into the loop and that's where it seems to be failing - namely when the buttons are clicked.
Console reports the following when either button is clicked:
Uncaught TypeError: Cannot read property 'play' of undefined
Specifically referring to this: sounds[i].play(); or sounds[i].pause();
Here's the JS:
var sounds = ['sound1', 'sound2'];
var howls = {};
for (var i=0; i<sounds.length; i++) {
howls[sounds[i]] = new Howl({
urls: ['http://powellian.com/assets/audio/' + sounds[i] + '.mp3', 'http://powellian.com/assets/audio/' + sounds[i] + '.ogg'],
volume: 1,
onplay: function() {
console.log('Playing: ' + sounds[i]);
$(sounds[i]).removeClass('static').addClass('playing');
$(sounds[i] + ' span.ascii-play').addClass('hide');
$(sounds[i] + ' span.ascii-pause').removeClass('hide');
},
onpause: function() {
console.log('Paused: ' + sounds[i]);
$(sounds[i]).removeClass('playing').addClass('paused');
$(sounds[i] + ' span.ascii-play').removeClass('hide');
$(sounds[i] + ' span.ascii-pause').addClass('hide');
},
onend: function() {
console.log('Finished: ' + sounds[i]);
$(sounds[i]).removeClass().addClass('static');
$(sounds[i] + ' span.ascii-play').removeClass('hide');
$(sounds[i] + ' span.ascii-pause').addClass('hide');
}
});
// PLAY btn
$('#' + sounds[i] + ' span.ascii-play').on('click', function (e) {
sounds[i].play();
});
// PAUSE btn
$('#' + sounds[i] + ' span.ascii-pause').on('click', function (e) {
sounds[i].pause();
});
}
I had a non-array/for-loop version working fine with 2 Howls, and the add/remove class stuff works fine so please ignore that.
I will eventually be generating 16 Howls from the array.
Here's a fiddle which includes the markup structure: Howler Fiddle
Any help would be appreciated, thanks in advance.

There are two issues that I see here:
You are referencing the variable i inside the click handler without maintaining scope. Because of this, it will always see i as the last value. You could use bind as one way of fixing this:
$('#' + sounds[i] + ' span.ascii-play').on('click', function (i2, e) {
sounds[i2].play();
}.bind(null, i));
You are trying to call play on sounds, which isn't holding the reference to the Howl object. You should be calling play on howls[sounds[i2]] instead.
EDIT: In this case it is just easier to use a forEach, so I've updated your fiddle to do that and fix the scoping issues here: http://jsfiddle.net/zmjz7sf3/1/.

Related

deleting elements created by jquery in a sequence

I'm trying to build my first plugin using jquery.
So far successful, but I'm stuck in deleting the notifications.
I was able to delete the notification on a click event.
Notification.prototype.destroy = function(element) {
var self = this;
element.closest('.notification-container').remove();
};
And I call that function inside init method.
Notification.prototype.init = function() {
var self = this;
self.$el.on('click', function() {
self.build();
});
self.$body.on('click', '.close', function() {
self.destroy(this);
})
};
Now I wanted to give a auto close option to the user, and I thought of using the setTimeout function, but as I've created the function passing the parameter as current element, I'm unable to get it.
Here's the pen.
Any help will be much appreciated.
Thanks!
You had several problems there:
The setTimeout function must be called upon display (and not upon build), otherwise it can be called even before you display the notification (hence your notification will not be automatically removed).
When you call the setTimeout in order to destroy the notification - you need to pass the container of the notification you just created, so the destroy function will be able to find the relevant element to remove (when you use the click option - you pass the X element, so it's easy to find the closest container, but when you use the setTimeout you must pass the container element himself).
I think all of the changes I made are in the build function, here it is:
Notification.prototype.build = function() {
var self = this;
var closeHTML = self.options.autoClose ? '' : '';
if (self.options.type == 'thumb') {
var $notificationHTML = $('<div class="notification-container">' +
'<i class="close">x</i>' +
'<div class="notification">' +
'<div class="thumb-container">' +
'<img src="' + self.options.src + '">' +
'</div>' +
'<p>' + self.options.text + '</p>' +
'</div>' +
'</div>');
} else {
var $notificationHTML = $('<div class="notification-container">' +
'<i class="close">x</i>' +
'<div class="notification ' + self.options.style + '">' +
'<p>' + self.options.text + '</p>' +
'</div>' +
'</div>');
}
self.$body.prepend($notificationHTML);
if(self.options.autoClose) {
setTimeout(function() {
self.destroy($notificationHTML);
}, 5000)
} else {
self.$body.on('click', '.close', function() {
self.destroy(this);
})
}
};
And a working codepen:
http://codepen.io/anon/pen/JKgPgB?editors=0010

Javascript Magento Create Account Preference Error

I am trying to create a second action on the Create New User Account form on Magento 1.9CE. We need an additional action to build an HTTP string and send to a URL as configured. So far we have built a script to pick up the fields, but this javascript isn't processing because the VarienForm is attached the event handler on document load. Could anybody shed some light on this code we have as to why its not processing?
<script type="text/javascript">
$(document).ready(function() {
window.setTimeout(function() {
$('#form-validate').on('submit', function( e )
{
var elements = this.elements;
e.preventDefault();
e.stopPropagation();
var subscribed = elements.is_subscribed.checked ? "y" : '';
var bglink = "http://suite9.emarsys.net/u/register_bg.php?owner_id=428212131&f=1481&key_id=3&optin=" + subscribed + "&inp_1=" + elements.firstname.value + "&inp_2=" + elements.lastname.value + "&inp_3=" + elements.email_address.value + "&inp_4=" + elements.year.value + "-" + elements.month.value + "-" + elements.day.value;
var img = $('<img width="1" height="1" src="'+bglink+'">')
.on('load error', $.proxy(function()
{
HTMLFormElement.prototype.submit.apply(this);
}, this))
.appendTo(this);
return false;
});
}, 2000);
});
</script>
If you are using jquery in your website may be jquery and prototype are conflict, to fix it:
- first of all you shoud add jQuery.noConflict(); to your website
- the second replace $ equal jQuery
ex:jQuery(document).ready(function() { })

Cause an array of events Backbone event:name

_.extend(object, Backbone.Events);
object.on("myalert:one", function(msg) {
document.body.innerHTML+=("eve1 " + ' msg:= '+msg+ ' ;name:= '+this.name);
},context);
object.on("myalert:two", function(msg) {
document.body.innerHTML+=(" eve2 " + ' msg:= '+msg+ ' ;name:= '+this.name);
});
I want сall all events are tied to this object with mask alert:.
object.trigger("myalert", "param");
There isn't any namespacing in Backbone.Events but you could add your own. For example, something like this:
obj.trigger_matching = function(re) {
var args = [''].concat([].splice.call(arguments, 1));
for(name in this._events) {
if(!name.match(re))
continue;
args[0] = name;
this.trigger.apply(this, args);
}
};
would allow you to say obj.trigger_matching(/^myalert:/, 1, 2, 3) and The Right Thing would happen.
Demo: http://jsfiddle.net/ambiguous/p8p5R/
That will trigger multiple 'all' events (one for each this.trigger.apply) which may or may not be what you want. If it isn't then replace the this.trigger.apply call with a custom version of the standard trigger so that you can trigger at most one 'all' event.

What is wrong with this js function?

Here is a part of my script:
function create(panel_id,iframe_source,handle_title) {
var temp1=document.createElement("a");
temp1.setAttribute("href","#");
var attr=document.createAttribute("onClick");
attr.nodeValue="showPanel(panel_id)";
temp1.setAttributeNode(attr);
temp1.className="controller";
temp1.innerHTML=handle_title;
div.appendChild(temp1);
}
function showPanel(panel_id) {
var elem = document.getElementById(panel_id);
elem.classList.toggle("show");
}
And here is the part where I call the first function:
create
When I call it, every element is created correctly and working except for the onClick attribute.I noticed that when I change the function like this:
...
attr.nodeValue="showPanel('test')";
...
everything is working fine..Can someone tell me what I have done wrong plz?
Change:
attr.nodeValue="showPanel(panel_id)";
to:
attr.nodeValue="showPanel('" + panel_id + "')";
there are two problems
1) onClick should be onclick
2) "showPanel(panel_id)"; should be
"showPanel('" + panel_id + "')";
try this
function create(panel_id,iframe_source,handle_title) {
var temp1=document.createElement("a");
temp1.setAttribute("href","#");
var attr=document.createAttribute("onclick");
attr.nodeValue="showPanel('" + panel_id + "')";
temp1.setAttributeNode(attr);
temp1.className="controller";
temp1.innerHTML=handle_title;
div.appendChild(temp1);
}
function showPanel(panel_id) {
var elem = document.getElementById(panel_id);
elem.classList.toggle("show");
}

Jquery Json not working properly

I have the following which works fine:
$('<li><a id=' + loc.locId + ' href="/DataEntry" rel="external">' + loc.locName + '</a></li>').appendTo("#btnList");
$("#btnList a").click(function () {
alert(siteName);
localStorage["dataEId"] = $(this).attr("id");
localStorage["dataESiteName"] = siteName;
localStorage["dataESysName"] = sysName;
localStorage["dataELocName"] = $(this).text();
}
When I have the following, I can't even get to the click to display an alert message:
$.getJSON('/Home/GetLocType', { "locId": loc.locId }, function (result) {
var str = JSON.stringify(result);
if (str == '1') {
$('<li><a id=' + loc.locId + ' href="/DataEntry" rel="external">' + loc.locName + '</a></li>').appendTo("#btnList");
} else {
$('<li><a id=' + loc.locId + ' href="/DataEntry/PotableForm" rel="external">' + loc.locName + '</a></li>').appendTo("#btnList");
}
$("#btnList").listview('refresh');
});
$("#btnList a").click(function () {
alert(siteName);
localStorage["dataEId"] = $(this).attr("id");
localStorage["dataESiteName"] = siteName;
localStorage["dataESysName"] = sysName;
localStorage["dataELocName"] = $(this).text();
}
Note sure what the difference is. I need to use Json as based on value, I need to go to a either of the 2 hyperlinks.
Use event delegation since anchor is created dynamically in your ajax call or bind the event (only for the added element) inside the ajax success callback. on syntax will work if your jquery version >= 1.7 for earlier versions take a look at live
$("#btnList").on('click', 'a', function () {
alert(siteName);
localStorage["dataEId"] = $(this).attr("id");
localStorage["dataESiteName"] = siteName;
localStorage["dataESysName"] = sysName;
localStorage["dataELocName"] = $(this).text();
}
Your first syntax works because it binds the click event to the anchor that exists underneath btnList, but it doesn't bind event to the ones added during the ajax calls in a later point in time.

Categories

Resources