Make a javascript function instead variables - javascript

Here I have a code that create a sidebar:
var side_bar_html = "<a href='javascript:google.maps.event.trigger(gmarkers[" + parseInt(gmarkers.length - 1) + "],\"click\");'>" + place.name + "</a><br>" + '<div class="raty" />' + "</br>";
$(side_bar_html).appendTo('#side_bar').filter('.raty').raty({
score : place.rating,
path : 'http://wbotelhos.com/raty/lib/img'
})
How I can create a function from this code to create a sidebar with function ...
So something like that:
function Create_a_sidebar_and_put_it_into_ID#sidebar () {
//for every marker to return html string
return "<div class='element'>"+place.name+"</br>"+place.rating+"</div>" + etc...
Becouse I have a problem with creating html, I dont know what to append where and I dont have contol over that
Is it possible?

If I'm understanding your question correctly, you're asking how you can take your first code block that creates a rating for a certain place, and refactor it so that you can arbitrarily create sidebars for places at will. So that's how I'll approach this answer.
As #Sime Vidas mentioned, you can start by taking the code that creates the sidebar itself and making that a function such as that below. I've modified the function a bit to take the javascript out of the href attribute (which is generally considered a bad practice) and replaced passing an html string into $.fn.init (which I've found steeply degrades performance) with using DOM methods to create elements. You also don't need the <br /> after your a element because divs by default are block elements.
function createSidebar(place) {
var $sidebarLink = $(document.createElement('a'));
var $raty = $(document.createElement('div'));
$sidebarLink.attr('href', '#').text(place.name).click(function(evt) {
evt.stopPropagation();
google.maps.events.trigger(gmarkers[parseInt(gmarkers.length - 1, 10)], 'click');
});
$raty.addClass('raty').raty({
score: place.rating,
path: 'http://wbotelhos.com/raty/lib/img'
});
return $([$sidebarLink, $raty]);
}
Now you can do things like
var $sidebar = $('#side_bar');
places.map(createSidebar).forEach(function($sidebarPart) {
$sidebar.append($sidebarPart);
});
Sorry if I'm off track with answering your question, but I think this is what you were asking. If not feel free to leave a comment and we can talk about it more!

Related

Initializing swiper sliders dynamically unexplainable behaviour

I have to create instances of swiper dynamically. These swipers have dynamically filled image contents. I have been fighting this the whole day with my lacking skills and cannot get this to work.
There are no javascript console errors, so I am assuming something is very fundamentally wrong but I don't know what it is.
Here is the code:
<!-- The sliders are initiated very standard way, i skipped showing them. These are my paginations where I cannot get the pagination to be rendered -->
<div class="secondary-0 swiper-pagination-clickable swiper-pagination-bullets"></div>
<div class="secondary-1 swiper-pagination-clickable swiper-pagination-bullets"></div>
<div class="secondary-2 swiper-pagination-clickable swiper-pagination-bullets"></div>
<script>
// I get lots of image data from php here
var imagearrays = <?php echo json_encode( $images_multiarray_js ); ?>;
// initialize variables for use in the loop.
var i;
var subNameArray = [];
var subSwiper = [];
// Loop through the imagearrays variable and initiate swipers.
for (i = 0; i < imagearrays.length; i++) {
subNameArray[i] = imagearrays[i].imagenames;
subSwiper = new Swiper('.subswiper-' + i, { // all my swiper-containers have extra class "subswiper-0" "subswiper-1" etc.
pagination: { // my main issue: I cannot get this pagination to render. WHY?
el: '.secondary-' + i, //my paginations have class like "secondary-0"
clickable: true,
renderBullet: function (index, className) {
return '<span class="' + className + '"><div class="pagination-ball"></div>' + subNameArray[index] + '</span>';
}
},
loop:true,
effect: 'fade',
clickable:true,
disableOnInteraction:false,
});
}
</script>
This is what my imagearrays variable looks like, just to show you that it's fine.
[
{"controllertype":false,"imagenames":["name1","name2"]},
{"controllertype":true,"imagenames":["name3","name4"]},
{"controllertype":false,"imagenames":["name5","name6"]}
]
I tried to go line by line in debugging JS mode, but it looks like the console simply leaps over the "new Swiper(..." line and everything inside it. Again, no errors in console.
How to feel really stupid:
Spend half a day figuring out why your code doesn't work
On a whim go check that your swiper selector class is attached to the correct html element and realize that it is not
Go cry in stackoverflow
I'm sorry guys, this question is useless. Everything works as intended with that d'oh fix.

Transfer data from one page to another jQuery Mobile

I using PhoneGap to create a Geolocation App following this excellent tutorial (link). Unfortunatelly, I'm having an issue that I can't figure out. The relevant parts that are giving me a headache are these:
//Section 1
$('#history').on('pageshow', function () {
tracks_recorded = window.localStorage.length;
$("#tracks_recorded").html("<strong>" + tracks_recorded + "</strong> workout(s) recorded");
$("#history_tracklist").empty();
for (i = 0; i < tracks_recorded; i++) {
$("#history_tracklist").append("<li><a href='#track_info' data-ajax='false'>" + window.localStorage.key(i) + "</a></li>");
}
$("#history_tracklist").listview('refresh');
});
//Section 2
$("#history_tracklist li a").on('click', function () {
$("#track_info").attr("track_id", $(this).text());
});
//Section 3
$('#track_info').on('pageshow', function () {
var key = $(this).attr("track_id");
$("#track_info div[data-role=header] h1").text(key);
var data = window.localStorage.getItem(key);
data = JSON.parse(data);
});
Section 1 works just fine, the data is stored, and the list is created without any issues. But then in Section 2 is when everything goes to hell. By clicking on the element, a new attribute (track_id) is supposed to be created, but it doesn't. Therefore, in Section 3, the "var key" won't get a value, and as a consequence, "var data" will be null also. As you can imagine, nothing works from there. What am I doing wrong here? I only included what I considered the relevant code, but if more is needed I'll do so. Thansk!
In section 2, I think you just need to delegate click handling to the "#history_tracklist" container, as follows :
$("#history_tracklist").on('click', "li a", function () {
$("#track_info").attr("track_id", $(this).text());
});
Without delegation you have a rule saying :
when any existing li a element within #history_tracklist is clicked execute my function
With delegation, you have a rule saying :
when any existing or future li a element within #history_tracklist is clicked execute my function

jQuery - remove li from array with delete image

I'm attempting to make a menu bar that can have <li> elements added and removed. So far so good, but when I try and remove them I'm running into issues. I've toyed with this for a couple hours and now I'm wondering if this whole process could just be made easier (maybe an object?).
Anyways, here's the full code (80 lines), with comments to follow along.
var tabs = $('.accountSelectNav');
var titles = [];
var listItems = [];
// when the page loads check if tabs need to be added to the ul (menu bar)
$(document).ready(function(e) {
if ($.cookie('listItems') != null) {
console.log('not null');
//return "listItems" to it's array form.
listItems = JSON.parse($.cookie('listItems'));
$('.accountSelectNav').append(listItems);
}
});
$('.selectTable td:first-child').on('click', function(e) {
$('#home_select').removeClass('navHighlight');
//grab the text value of this cell
title = $(this).text();
$.ajax({
url:'core/functions/getAccountId.php',
type: 'post',
data: {'title' : title}
}).fail (function() {
alert('error');
}).done(function(data) {
accountId = $.trim(data);
// store values in the cookie
$.cookie('account_id', accountId, {expires : 7});
$.cookie('title', title, {expires : 7});
window.location = ('home_table.php');
});
// make sure the value is NOT currently in the array. Then add it
var found = jQuery.inArray(title, titles);
if (found == -1) {
titles.push(title);
addTab();
}
// make sure the value is NOT currently in the array. Then add it
found = jQuery.inArray(title, listItems);
if (found == -1) {
addListItem();
//place <li>'s in cookie so they may be used on multiple pages
$.cookie('listItems', JSON.stringify(listItems));
};
});
$("body").on("click", ".deleteImage", function (e) {
var removeTitle = $(this).closest('li').find('a').text();
var removeItem = $(this).closest('li')[0].outerHTML;
//remove title from "titles" array
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
//remove <li> from "listItems" array
listItems = jQuery.grep(listItems, function (value) {
return value != removeItem;
});
// this shows the <li> is still in the listItemsarray
console.log(listItems);
// put the array back in the cookie
$.cookie('listItems', JSON.stringify(listItems));
removeTab(this);
});
$("body").on("mouseover", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').show();
});
$("body").on("mouseleave", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').hide();
});
function addTab() {
tabs.append('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
};
function removeTab(del) {
$(del).closest('li').remove();
}
function addListItem() {
var s = ('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
listItems.push(s);
}
So you see I have two arrays of equal length that should always be the same length. One stores the title to be displayed in the tab, the other holds the html for the <li> which will be appended to the <ul>. I have no problem removing the title from its array. However removing the <li> from it's array is becoming a rather big hassle. You see when I get the <li> element after its been inflated the html inside does not exactly match what was put in, the browser adds style elements.
Example, the variable "removeItem" represents the html value of the selected <li> I wish to remove. It looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage" style="display: inline;"></li>
yet the value in my array "listItems" looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage"/></li>
So my attempt at removing it from my array always fails because they aren't a perfect match.
Now my question is how do I remove this <li> item? Also is there an easier way to do this whole process and I'm just not seeing it?
Thanks for your time.
EDIT
Fiddle by request here
Easiest way I can explain it.
Click the link to the fiddle.
Click any cell in the "App Name" column
This will add a <li> to the <ul> (menu) above of the table
When you hover over the <li> a picture appears
Click the picture
This should remove the <li>, both from the <ul> and from the array listItems
right now it does not
In the process of making this easier to check, I've taken your JSFiddle and did the following:
removed extra console.log and comments
removed interaction with cookies (since I did not have them in the first place, I figured they wouldn't just the first scenario)
After doing so I reached a point (you can see it here) where the desired functionality just works.
I even went ahead and removed the ajax stuff because that alert was driving me crazy. (here)
Since this works fine, my guess is that your issue lies between the lines that I removed.
Your usage of cookies is as follows:
To load existing tabs and add them back again
To save account_id and title, which is not used back again
To persist the listItems after a new item has been added
I then opened up the console with your version of the fiddle and the execution of javascript stops at $.cookie() with the error undefined is not a function.
This clearly indicates that the issue present in the Fiddle is that jQuery.cookie is not present and so those calls are halting the execution of the rest of your script. This also explains why it just started working when I took them out.
I posted the whole process of how I got there to indicate how I trimmed down the problem to specific parts, which is useful to reduce the problem space. When you're out of options and reach a place when you're lost, it's easier to post a question with less code and the specific part of the problem that you've identified. This will help you in finding the issues that you're facing and StackOverflow to provide proper answers to your questions.
Hope it helps!
Here is the solution I came up with. It should be much easier for people to understand than my original post. Although it's a long read it may be worth it, especially for new developers.
The point of this code is to make a menu bar out of an un-ordered list or <ul>. The menu bar needs to be used on multiple pages. So I'll be using cookies.
I start with this code to get a text value from my table.:
$('.selectTable td:first-child').on('click', function(e) {
// This value will be used later for the name of the tab or `<li>` inside our menu bar or `<ul>`
title = $(this).text();
});
Then I place the value in an array. I do this only if the array does not already have this string inside it. I do not want duplicates:
var found = jQuery.inArray(title, titles);
var titles = [];
if (found == -1) {
titles.push(title);
}
Then I store the array into a cookie, using a library like this:
$.cookie('titles', JSON.stringify(titles));
Now when any page loads that needs this menu bar I run this code to check if there are any values:
$(document).ready(function() {
if ($.cookie('titles') != null) {
titles = JSON.parse($.cookie('titles'));
}
});
Now I need to loop through the array. When I loop through the array I have to do 3 things:
1) Grab the string value.
2) Add the html to my new string so it becomes a list item or <li>.
3) Append the newly created <li> to our <ul>.
Like so:
for(var i = 0; i < titles.length; i++) {
var str = titles[i];
var listItem = '<li class="navHighlight">'
+ '<a href="#">'
+ str
+ '</a>'
+ '<a href="#">'
+ '<img src="images/delete.png" class="deleteImage"/>'
+ '</a>'
+ '</li>';
$('.accountSelectNav').append(listItem);
}
Now, if I want to remove this <li> I click the delete image found inside our <li>. What delete image you say? Look at the html I added again. You will see I add an <img> tag in there.
Now delete like so:
$("body").on("click", ".deleteImage", function (e) {
// grabs the text value of my li, which I want to remove
var removeTitle = $(this).closest('li').find('a').text();
// runs through my titles array and returns an array without the value above
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
});
Then I simply place the new array inside my cookie once again. Like this:
$.cookie('titles', JSON.stringify(titles));
And finally I remove the tab like this:
removeTab(this);
function removeTab(del) {
$(del).closest('li').remove();
}
Yay, I'm done. So now, if anyone has a more elegant way of accomplishing this I'm listening. I have no doubt there's a better way, javascript/jQuery isn't even close to my strong point.
The full code can be found here.

Optimizing code to define variables only once, code only works when the vars are in change function and for the code outside change I redefine?

Pretty sure I know the solution... would write .on('change','load', function(){}
correct? <-- Tested didn't work? so I am up to your solutions :)
Sushanth -- && adeneo both came up with great solutions, this is a good lesson in optimizing code... It's gonna be hard to choose which answer to go with, but I know this is going to help me rethink how I write... I dont know what I do without this forum, id have to learn this stuff in college.
This is purely a question out of curiosity and bettering my skills, as well as giving you guys a chance to display your knowledge on jQuery. Also to prevent any sloppy writing.
I have a radio based switch box, the markup looks like this, the id's and on/off values are generated by the values in my array with PHP...
<span class="toggle-bg">//This color is the background of the toggle, I need jQuery to change this color based on the state on/off
<input type="radio" value="on" id="_moon_page_header_area1" name="_moon_page_header_area">//this is my on value generated by the array
<input type="hidden" value="_moon_page_header_area" class="switch-id-value">// I create this input because I have multiple checkboxes that have the ID _moon_ARRAYVALUE_area1
<input type="radio" value="off" id="_moon_page_header_area2" name="_moon_page_header_area">// off value
<input type="hidden" value="_moon_page_header_area" class="switch-id-value">//_moon_ARRAYVALUE_area2
<span class="switch"></span>// the switch button that changes
</span>
Hope that makes sense and the comments are clear
Here is the jQuery
var value = $('.toggle-bg input.switch-id-value').val()
var moon1 = $('#'+value+'1').is(':checked');
var moon2 = $('#'+value+'2').is(':checked');
var static_slide = $('._moon_staticarea_height');
var toggle = $('.toggle-bg');
if(moon1){
toggle.css({'background-color': '#46b692'});
static_slide.hide()
} else
if (moon2){
toggle.css({'background-color': '#333'});
static_slide.show()
}
$('.toggle-bg').change(function () {
var value = $('.toggle-bg input.switch-id-value').val()
var moon1 = $('#'+value+'1').is(':checked');
var moon2 = $('#'+value+'2').is(':checked');
var static_slide = $('._moon_staticarea_height');
var toggle = $('.toggle-bg');
if(moon1){
toggle.css({'background-color': '#46b692'});
static_slide.slideUp()
} else
if (moon2){
toggle.css({'background-color': '#333'});
static_slide.slideDown()
}
});
it looks longer than it really is, its just repeating it self, one is on load so that it gives the correct color on load of the page, and then inside the change function we need to change colors..
How do I write it so I only have to use variables one time (so its cleaner) is there a better way to optimize it... Just NOW thinking after writing this I could put it in one function .on('load', 'change', function() {}
I just now thought of that, but I wrote all this so I am going to see what others think...
You'd do that by having the function in the change event handler, and on the end you chain on a trigger('change') to make it work on pageload :
$('.toggle-bg').on('change', function () {
var value = $('.toggle-bg input.switch-id-value').val(),
moon1 = $('#' + value + '1').is(':checked'),
slider = $('._moon_staticarea_height'),
toggle = $('.toggle-bg');
toggle.css('background-color', (moon1 ? '#46b692' : '#333'));
slider[moon1?'slideUp':'slideDown']();
}).trigger('change');
As radiobuttons can't be unchecked, it's either moon1 or moon2, which means checking one of them should be enough.
.on('change','load',
supposed to be
// Remove the comma separator if you want to bind the same handler to
// multiple events.
.on('change load',
And you can remove the one separately written out and enclose it in a function (if multiple instances of the class toggle-bg)
or just trigger the change event.(If there is a single instance of a class)
This will just run the same functionality when the page loads.
var toggle = $('.toggle-bg');
toggle.change(function () {
var value = $('input.switch-id-value', this).val(),
moon1 = $('#' + value + '1').is(':checked'),
moon2 = $('#' + value + '2').is(':checked'),
static_slide = $('._moon_staticarea_height');
if (moon1) {
toggle.css({
'background-color': '#46b692'
});
static_slide.slideUp()
} else if (moon2) {
toggle.css({
'background-color': '#333'
});
static_slide.slideDown()
}
}).change();

How to simplify code to add new elements to a page with jQuery?

I've written the following code to add a clickable "link button" to a section of my page.
var linkButtonHtml = "<a data-makeId='" + makeId + "' href='javascript:expandMake(" + makeId + "," + categoryId + ")'>+</a> " + makeName;
var divHtml = "<div style='display:none' class='models' data-makeId='" + makeId + "'></div>" + "<br/>";
html += linkButtonHtml + divHtml;
$('#linkDiv').html(html);
The code works fine, but it's ugly and difficult to read with all the string concatenation.
As you can see, I am building anchor elements and div elements with string concatenation. The target of my anchor element is a javascript function invocation with two arguments. Is there a good jQuery way to improve the readability of this code?
I'm not sure if this really improves readability is here is a 100% jQuery solutions:
$(html)
.append(
$('<a />')
.attr('data-makeId', makeId)
.attr('href', 'javascript:void(0);')
.click(function(event)
{
// Prevent clicking the link from leaving the page.
event.preventDefault();
expandMake(makeId, categoryId);
})
.text('+'))
.append(
document.createTextNode(makeName)
)
.append(
$('<div />')
.addClass('models')
.attr('data-makeId=', makeId)
.hide());
Where "html" in $(html) is the html variable you have in your sample.
jQuery offers an option for a second argument when creating elements.
var linkButton = $('<a>',{'data-makeId':makeId,
href:'#',
click:function(){expandMake( makeId, categoryId )},
text:'+'
});
var div = $('<div>',{ style:'display:none',
'class':'models',
'data-makeId': makeId
})
.after('<br>');
$('#linkDiv')
.empty()
.append(html)
.append(linkButton)
.append( makeName )
.append(div);
EDIT: Fixed an issue where makeName was not appended.
Only real way is either abstracting some of your tag generation or spread the script out a little to make it more readable : http://jsfiddle.net/3dYPX/1/
Your also using jQuery so you might want to consider changing the way you trigger the javascript. Try looking into the .live() event. (Ill just get an example up, not that its very important)
Using live event for unobtrusive javascript:
http://jsfiddle.net/3dYPX/2/
It is all being done inside of the onLoad event at the moment, just to use as an example.
Use a template library such as
jQuery Templates instead of inlining
HTML.
Instead of using "javascript:" URLs, attach event handlers to the generated DOM fragments.
Refrain from using inline styles.
Something like:
$('#linkDiv')
.empty()
.append($.tmpl(myTemplate, {
makeId: makeId,
makeName: makeName,
categoryId: categoryId
}))
.click(function () {
var makeId = $(this).attr("data-makeId");
if (makeId) {
expandMake(makeId, $(this).attr("data-categoryId"));
}
});
Where myTemplate has the content:
${makeName}
<div class="models" data-makeId="${makeId}"></div>
Instead of using an inline style to initially hide the models, hide them all with a general CSS rule, and then selectively show them with a class:
.models { display: none }
.models.shown { display: block }
Just add the "shown" class to show a certain block of models.
Here you go:
$('#linkDiv').empty().append([
$('+').data('makeId', makeId).click(function(e) {
e.preventDefault();
expandMake(makeId, categoryId);
})[0],
$('<span>').text(makeName)[0],
$('<div class="models">').data('makeId', makeId).hide()[0],
$('<br>')[0]
]);
Live demo: http://jsfiddle.net/cncbm/1/
Consider this:
$('#linkDiv').data({'makeId': makeId, 'categoryId': categoryId}).empty().append([
$('+').click(expandMake)[0],
$('<span>').text(makeName)[0],
$('<div class="models">').hide()[0]
]);
So, you define that data-stuff on the parent DIV (the common parent) and you re-factor the expandMake function so that it reads those data-values from the parent DIV instead of passing them as arguments.

Categories

Resources