Audio Queued Not immediate playing - javascript

I am working on an Audio related file in html5.
I used following function to change the audio
function Audioplay(id) {
var id=id.split('Symbols')[1];
var FolderRedirect=id.split('')[0];
$("#audio").get(0).pause();
$("#audio").attr('src', ' ');
$("#audio").attr('src', 'assets/audio/'+Folder[FolderRedirect]+'/sound_'+id+'.mp3');
$("#audio").get(0).play();
};
It changes the audio, but it will be played completely the first time. How can I play it immediately onclick? Thanks

If you look at your function, you're calling play() as the last line. Remove it, and instead add it as a click handler on whatever element you're using as a control.
There are other cleanups you should consider:
Function names conventionally begin with a lowercase letter--functions beginning with an uppercase letter imply that you should use the new operator to create one.
You redeclare id as a local variable, even though it is passed in as an argument.
You reference the variable Folder from within the body of your function. That makes it hard to reason about what is happening there. Consider either passing the folder array (note the correct case) into the function as an argument, or even better, separating the derivation of your redirect into a separate function.
You force jQuery to find the #audio element 4 times. Instead, store it in a local variable so jQuery only has to look it up once.
A reworked function:
function playAudio($audio) {
$audio.get(0).play();
}
function normalizeId(rawId) {
var idParts = id.split('Symbols');
return idParts[1];
}
function getFolderRedirectFromNormalizedId(normalizedId) {
return normalizedId.split('')[0];
}
function getSourcePathFromId(id) {
var folders, folderRedirect, normalizedId;
folders = [/* Initialize your folder array */];
normalizedId = normalizeId(id);
folderRedirect = getFolderRedirectFromNormalizedId(normalizedId);
return 'assets/audio/' + folders[folderRedirect] + '/sound_' + normalizedId + '.mp3';
}
function initializeAudio(id) {
var src, $audio;
$audio = $("#audio");
$audio.get(0).pause();
$audio.attr('src', ' ');
src = getSourcePathFromId(id);
$audio.attr('src', src);
$('.control-you-want-to-click').click(function() {
playAudio($audio);
});
}
initializeAudio();

Related

Accessing a JavaScript / jQuery Instance only once

I have a jQuery function which is called on several events (button click, change etc.)
This function is called in the documentReadyFunction and is feeded with start values..
everytime I call this function, parameters will be passed to the function.
My problem is: I don't want to create a new Object each time I call the function, because if I set a variable which decides if a part of the function is beeing executed or not, will be always overwritten..
What do I have to do, to access the first created instance instead of creating always a new one with every function call..
Down below is a simplyfied version of my function.. Maybe you understand my problem better then.
$.fn.doSomething = function(param1) {
var localParam = param1;
var amIcalledMoreThanOnce = parseInt(0, 10);
if (param1 == 1) {
amIcalledMoreThanOnce = amIcalledMoreThanOnce + 1;
if (amIcalledMoreThanOnce == 1) {
$('#run').val(amIcalledMoreThanOnce);
// fill form fields with URL parameters
// This shall be executed only once after getting the URL vals
} else {
// set the localParam to 0 to exit this loop and reach the outter else..
localParam = 0;
$.fn.doSomething(localParam);
}
} else {
$('#run').val(amIcalledMoreThanOnce);
// use the User Input Data not the URL Params
}
};
$.fn.doSomething(1);
$.fn.doSomething(1);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<input type="number" id="run">
you can use this pattern:
var nameOfYourFunction = (function() {
var initializedOnlyOnce = {};
return function() {
//use initializedOnlyOnce here.
}
})();
here what you see is; you create and run a function immediately when the code is run. The outer function immediately returns the inner function and it's assigned to nameOfYourFunction. Then you can use the nameOfYourFunction(); just as any other function. However any varible declared in the outer function will be available to the nameOfYourFunction() and initializedOnlyOnce will never be initialized again.

Loop a function using timeout and pass variables

Alright I have a feeling this is simple and I'm overlooking something.
I have an array of data that I'm passing into the function containing 300 rows.
The function itself picks out a random box to update, and a random array element to pass (0-299) and then updates that box.
The first Iteration is fine. The second returns "Uncaught ReferenceError: rand_ad is not defined "
function loop(last_ad, last_ad_box, ads_array){
// start
while(rand_ad == last_ad){
var rand_ad = get_rand(299);
}
while(rand_ad_box == last_ad_box){
var rand_ad_box = get_rand(29);
}
console.log(ads_array[rand_ad]);
// update the ad
// update_ad('.addno-'+rand_ad_box, ads_array[rand_ad]);
//recall itself to continue looping after 1 second
t = setTimeout("loop(rand_ad, rand_ad_box, ads_array)",3000);
}
function get_rand(max){
var rand = Math.floor(Math.random()*max) + 1;
return rand;
}
I think it might be the quotation marks around the function loop, that it's treating the variables inside as strings instead of actual variables, but I can't get it to render out before it snaggs the error.
Any ideas?
Your guess is correct. Change the timeout line to this:
t = setTimeout(loop, 3000, rand_ad, rand_ad_box, ads_array);
Passing strings to setTimeout is a security risk and not recommended. Also, it doesn't execute the code until the timeout occurs, so the variables are dereferenced after the function has exited.
If you need it to work in IE, then you'll have to use this:
t = setTimeout(function () {
loop(rand_ad, rand_ad_box, ads_array);
}, 3000);

Is there a way to create a function that can be either a click event or an onload event, depending on the class of the body?

Basically the Title states the question, but the situation is this (it's difficult to replicate with jsbin or anything else, so I'm going to try to solve without doing that).
I have a function that is called on the click of a button. The click event will tell the output what font will be used. However, on certain pages, I want the font to be declared by the class of the body element and not on the click of a button.
I'm running into two problems.
When I try to pass an argument and receive a parameter, the parameter is an event, rather than whatever I want to pass.
If I pass the event as the first parameter and the font I want as the second, I get undefined as my font variable and the function does not work.
Any help on making a function be flexible in this way would help me out a lot.
Edit: Here's a simplified version of what I've got
function fontSelection(font) {
var self = $(this),
inputOne = $('li:eq(0) input').val(),
inputTwo = $('li:eq(1) input').val(),
inputThree = $('li:eq(2) input').val(),
resultOne = $('div:eq(0)'),
resultTwo = $('div:eq(1)'),
resultThree = $('div:eq(2)');
font = font || $('div.font').attr('title').toLowerCase();
resultOne.removeClass().addClass(inputOne + ' someclass ' + font);
resultTwo.removeClass().addClass(inputTwo + ' someclass ' + font);
resultThree.removeClass().addClass(inputThree + ' someclass ' + font);
}
Rather than pass your function directly to the event registration, you pass an anonymous function that then calls your function with the desired arguments.
So, rather than this:
$("#myButton").click(callMyFunction);
You use this which allows you to specify the exact arguments you want:
$("#myButton").click(function(e) {
callMyFunction(myParam1, myParam2);
});
If you want to preserve, the value of this in your function, then you need to use .call() like this to explicitly set it appropriately in your function:
$("#myButton").click(function(e) {
fontSelection.call(this, myParam1, myParam2);
});
Or, just pass it as an argument and use the argument in your function instead of this:
$("#myButton").click(function(e) {
fontSelection(this, myParam1, myParam2);
});
Try this on for size: A function that, if given an argument, sets the font to be used. If the argument is not set, then reads the body tag for a font.
$(function () {
if ($('body').hasClass('your class for onload change')) {
// change font
} else {
$('button').click(your_function);
}
});
Edit:
if you want to use this in your function and want it to reference on body in first case and some another dom element in second case, you can use call or apply
$(function () {
if ($('body').hasClass('your class for onload change')) {
fontSelection.apply($('body').get(0), [font]);
} else {
$('button').click(function () {
fontSelection.apply(this, [font]);
});
}
});

create a javascript function programmatically

Need this for the youtube api // the onStateChange callback functions!
I want to programmatically create functions which will listen to the "onStateChange" event emitted by several youtube player. Adding the listener works already:
function onYouTubePlayerReady(playerId) {
var ytpStateManager = playerId +"_StateManager";
document.getElementById(playerId).addEventListener("onStateChange", ytpStateManager );
...
The function I need to create based on the playerId variable ("ytp_1", "ytp_2", ...) is
function ytpStateManager(newState) {
ytpStateHelper(playerId , newState);
}
So the result for the playerId "ytp_1" would look like this:
function ytp_1_StateManager(newState) {
ytpStateHelper("ytp_1", newState);
}
Works also but right now I need to add them manually for each player, which is not what I need. I want to create them automatically when a new player sends a readyState event.
My problem is that it seems like these functions need to be a global functions to work properly. I tried several options for days now. My problem is that I do not know how (if there is a way) to define a global function, incl. the function name, programmatically, based on another variable.
Its a bummer that the ytp does not emit an event which includes the state AND the player/target. Would make things much easier. All this is basically the workaround as I need all to do stuff on all stateChanges.
If there is a better/simpler way, PLEASE let me know :) Otherwise a solution for this question is highly welcome.
Maybe there is a way to rerout the event, to make it more "accessible"?
I read in the spec that .addEventListener also takes a object, so I tried to bind the event to a dedicated object. But again, it did not get triggered. Feels like I tested everything ...
UPDATE
I am now switching to the iframe player (from swfobject) because that one provides an event which includes playerId and state :D Yeahhh!! After spending week with the wrong ytplayer this feels like a great advancement. Also seems like yt wants us to use the iframe player which can dynamically use html5 when supported.
You create a function that returns a function:
function createStateManager(playerId) {
return function (newState) {
ytpStateHelper(playerId , newState);
}
}
Then you call your function factory when setting up the event listener:
var player = document.getElementById(playerId);
player.addEventListener("onStateChange", createStateManager(playerId));
DEBUGGING
I'm not sure why that's not working, but here is a debugging suggestion. I suspect you may not be getting the playerId on your onYouTubePlayerReady handler.
function onYouTubePlayerReady(playerId) {
console.log('Player ready. The player id is: ' + playerId);
var ytpStateManager = playerId +"_StateManager";
var player = document.getElementById(playerId);
player.addEventListener("onStateChange", createStateManager(playerId));
}
function createStateManager(playerId) {
return function (newState) {
console.log('State changed for player ' + playerId + '. New state is ' + newState);
ytpStateHelper(playerId , newState);
}
}
Could you try that, and post what you get from both console.log calls?
1)You can create Function object new Function([params], "BODY")
So you can combine body of your function as string variable and put into as BODY
Example:
var twoNumAverage = new Function("x", "y", "return (x + y)/2")
console.log(twoNumAverage(3,7))
2)And new can create dynamically name and BODY
Example
var globalObject ={};
var nameFn ='MyNewFunction';
var createFn = function(object,functionName, Body){
object[functionName]= new Function(Body);
}
createFn(globalObject,nameFn,"return (arguments[0] + arguments[1])/2");
You can call your new function:
globalObject[nameFn](10,20);
Result: 15
Please note that in body your function you can get params via collection arguments
window["foo"+"bar"] = function(){ console.log("foobar is called"); }
Here's a way to create a named proxy function that executes another function with the context you supply.
function createNamedProxy(name, fn, context) {
var template = [
'(function #name() {',
' #name.fn.apply(#name.context || window, arguments);',
'})'
].join('').replace(/#name/g, name),
result = eval(template);
result.fn = fn;
result.context = context;
return result;
}
// Example Usage
var anonymous = function() { alert( document === this ); },
named = createNamedProxy('Named', anonymous, document);
// Will alert 'true'
named();
The solution above creates a function that can create and return a named function that executed whatever you'd like. If you don't supply context, it will assume the window object just like a normal anonymous function would. To create the solution you wanted you would do:
var varName = 'ytp_1';
window[varName + '_StateManager'] =
createNamedProxy(varName + '_StateManager', function(newState) {
ytpStateHelper(varName, newState);
});
Where varName could be any programmatic prefix you'd like. When invoking ytp_1_StateManager() you would pass in your newState value and the code would call ytpStateHelper with your variable name and the newState.
Hope this helps.

Confused by this - getting error "this.myfuntion() is not a function"

Background: I am trying to edit a zen cart horizontal pop out menu to make the popout open inline within the menu. The problem I am having is that I am struggling to get my head around the javascript/jquery that came with it.
Without posting the whole thing the structure of the code is something like this:
(declare some vars)
//some functions like this:
function funcname(obj) {
//do something
}
//then one big master function like this:
function bigfunc(arg1, arg2, arg3, arg4, arg5) {
//declare some vars based on this
this.varname1=varname1;
this.varname2=varname2;
//declare some functions inside the big function
this.innerfunc1= function() {
//do stuff
}
this.innerfunc2= function() {
//do stuff
}
}//end of big function
//then goes on to declare init function
function initfunc(){
//this creates new bigfunc(arg1 arg2 arg3...) for each main menu item
}
//finally calls init function with
window.onload = initfunc();
Now on to my confusion -
1) firstly for clarification, am I correct in thinking based on all the this's floating about in bigfunc() and the fact that it is called with new bigfunc() that this is creating an object?
2)My current problem is with one of the functions inside bigfunc() which looks like this:
this.slideChildMenu = function() {
var divref = this.children[0].div;
var ulref = this.children[0].ul;
var maxwidth = this.children[0].width;
var nextWidth;
if (this.isMouseOnMe || this.isMouseOnChild()) {
nextWidth = divref.offsetWidth + slideSpeed_out;
if (nextWidth >= maxwidth) {
this.finishOpeningChild(divref, ulref, maxwidth);
} else {
ulref.style.left = nextWidth - maxwidth + "px";
divref.style.width = nextWidth + "px";
setTimeout("slideChildMenu('" + this.getId() + "')", slideTimeout_out);
}
}
Now my plan is to alter this to use jquery show to open the element so I tried this:
this.slideChildMenu = function() {
var divref = this.children[0].div;
var ulref = this.children[0].ul;
if (this.isMouseOnMe || this.isMouseOnChild()) {
$(divref).show(function(){
this.finishOpeningChild(divref, ulref);
});
}
}
But I am getting this-> TypeError: this.finishOpeningChild is not a function
Now, there is a lot of other stuff going on in this js so I wouldnt dream of asking someone on here to do my work for me, but I am hoping that if someone can explain to me why this function is not a function I may be able to work the rest out.
NOTE: I thought this was to do with the scope of "this" but the value of this appears to be exactly the same in both versions of the code.
I know this is a long one but your help is greatly appreciated.
The value of this in a function is called the "context" in which the function runs. In general, whenever you pass a callback function as an argument (as you do with $(divref).show(function() {...})), the function can run the callback in whatever context it wants. In this case, the jQuery show function chooses to run its callback in the context of the element being animated.
However, you want access to the value of this at the time the anonymous callback function is defined, rather than when it is run. The solution here is to store the outer value of this in a variable (traditionally called self) which is included in the scope of the newly-defined function:
this.slideChildMenu = function() {
//...
var self = this;
$(divref).show(function(){
self.finishOpeningChild(divref, ulref);
});
}
I am thinking that the jQuery selector has changed the scope of this.
In your example $(this); would refer to object being animated per jQuery api docs:
If supplied, the callback is fired once the animation is complete. This can be useful for stringing different animations together in sequence. The callback is not sent any arguments, but this is set to the DOM element being animated. If multiple elements are animated, it is important to note that the callback is executed once per matched element, not once for the animation as a whole.
If the object in question is instantiated you can call it with dot notation without using this like bigFunc.finishOpeningChild(divref, ulref);
You're probably a little confused about scope, it's not always easy keeping track, but doing something more like this:
var site = {
init: function(elm) {
self=site;
self.master.funcname2(self.varname1, elm); //call function in master
},
funcname: function(obj) {
//do something
},
varname1: 'some string',
varname2: 3+4,
master: function() {
this.varname3 = sin(30);
this.funcname2 = function(stuff, element) {
site.funcname(element); //call function in 'site'
var sinus = site.master.varname3; //get variable
}
}
}
window.onload = function() {
var elm = document.getElementById('elementID');
site.init(elm); //call init function
}
usually makes it a little easier to keep track.

Categories

Resources