Combine Several Similar Variable Declarations - javascript

This is a small part of a script I'm working on that generates an eBay listing with the user's photos and text. The script outputs all the code as a string for copying and pasting, as well as rendered HTML/CSS/JavaScript for a preview. For that reason, href and src attributes need to be populated dynamically, since I don't know them in advance. This snippet in particular seems to me to be too redundant. I'm not sure how to go about this other than how I have it currently.
I posted a working piece of this code and a fiddle on CodeReview, hoping to get general suggestions on my code. Since this is a specific issue, I'm posting it here.
Here are the first two statements I have which populate the href to the full-size image:
var fullSizeSrc1 = $('#slide-upload tr:first td:first a').attr('href');
if (fullSizeSrc1) {
fullSizeSrc1 = fullSizeSrc1;
} else {
fullSizeSrc1 = '';
}
var fullSizeSrc2 = $('#slide-upload tr:nth-child(2) td:first a').attr('href');
if (fullSizeSrc2) {
fullSizeSrc2 = fullSizeSrc2;
} else {
fullSizeSrc2 = '';
}
I currently have seven of those, and seven of these (these populate the src attribute for the thumbnails):
var thumbSrc1 = fullSizeSrc1;
if (thumbSrc1) {
thumbSrc1 = thumbSrc1.replace(/files/g, 'files/thumbnail');
} else {
thumbSrc1 = '';
}
Here's a portion of the script that contains the HTML markup to be generated, and populates the proper attributes with the above variables:
'<div id="mblSlide">' +
'<img data-name="one" alt="" src="'+fullSizeSrc1+'">' +
'<img data-name="two" alt="" src="'+fullSizeSrc2+'">' +
'</div>' +
'<div id="mblThumbs">' +
'<img style="border:1px solid #fff;margin:3px" data-name="one" alt="" src="'+thumbSrc1+'">' +
'<img style="border:1px solid #fff;margin:3px" data-name="two" alt="" src="'+thumbSrc2+'">'
'</div>' +
I hope that's clear. If not, please let me know what was unclear and I'll try my best to, ah, clarify :) Thanks in advance for all the great work you guys do.

As mentioned in the comments
if (fullSizeSrc1) {
fullSizeSrc1 = fullSizeSrc1;
}
Doesn't really do anything or change the value of fullSizeSrc1. You should change it to:
if(!(fullSizeSrc1)){
fullSizeSrc1 = '';
}
//or if(fullSizeSrc1 === undefined)
To your original question about not retyping code:
I consider it a tell when you find yourself name different instances of the same type of data as var1, var2, var3, var4. Once you start counting, you should probably consider using an array.
So we have as a start:
var fullSizeSrc = [];
var fss = $('#slide-upload tr:first td:first a').attr('href');
if(!fss){
fss = '';
}
fullSizeSrc.push();
But then we still have the problem of writing the same code 7 times right? You should look at what the difference is between each version of the same code. The first was the variable name, we solved that by using an array.
The second difference is that we indexing into list of child elements. So assuming we have 7 elements to look at 1 .. 7. We can use a simple for loop to cut out the other code.
var fullSizeSrc = [];
var total = 7;
for(var i =1, i <= total; i++){
var fss = $('#slide-upload tr:nth-child('+i+') td:first a').attr('href');
if(!fss){
fss = '';
}
fullSizeSrc.push();
}
But what if we didn't know the list size? Luckily that nth-child jquery function can return a list of all child elements
var fullSizeSrc = [];
var links = $('#slide-upload tr:nth-child(n) td:first a');
$(links).each(funcion(i, a){
var link = $(a).attr('href');
if(!link){
link = '';
}
fullSizeSrc.push(link);
})

Related

Update href text value dynamically using JQuery

There are href links on the page, its text is not complete. for example page is showing link text as "link1" however the correct text should be like "link1 - Module33". Both page and actual texts starts with same text (in this example both will starts with "link1").
I am getting actual text from JSON object from java session and comparing. If JSON text starts with page text (that means JSON text "link1 - Module33" startsWith "link1" (page text), then update "link1" to "link1 - Module33".
Page has below code to show the links
<div class="display_links">
<ul id="accounts_links_container">
<li id="accounts_mb_2_id"><a href="javascript:void(0)" class="linksmall"
id="accounts_mb_2_a"> link1 </a></li>
<li id="accounts_mb_11_id"><a href="javascript:void(0)" class="linksmall"
id="accounts_mb_11_a"> link2 </a></li>
.
.
.
// more links
</ul>
</div>
Note : li id is not static its different for each page text, however ul id is static.
I am reading correct & full link text from JSON object (from java session) as below
var sessionValue = <%= json %>; // taken from String array
and reading page text as below :-
$('.display_links li').each(function() { pageValue.push($(this).text()) });
sessionValue has correct updated text and pageValue has partial texts. I am comparing using below code
for(var s=0; s<pageValue.length; s++) {
var pageLen = $.trim(pageValue[s]).length;
for(var w=0; w<sessionValue.length; w++) {
var sesstionLen = $.trim(sessionValue[w]).length;
var newV = sessionValue[w].substring(0, pageLen);
if($.trim(newV)==$.trim(pageValue[s])){
**// UPDATING VALUES AS BELOW**
pageValue[s]=sessionValue[w];
}
}
}
I am trying to update page value text to session value text as pageValue[s]=sessionValue[w]; (in above code) but its not actually updating the values. Sorry for the poor comparing text logic.
Please help, how to update it dynamically in the loop after comparing to make sure I am updating the correct link text.
pageValue[s]=sessionValue[w]; just updates the array; it has no effect whatsoever on the li's text.
If you want to update the li's text, you need to do that in your each. Here's an example doing that, and taking a slightly more efficient approach to the comparison:
$('.display_links li a').each(function() {
var $this = $(this);
var text = $.trim($this.text());
var textLen = text.length;
for (var w = 0; w < sessionValue.length; ++w) {
var sessionText = $.trim(sessionValue[w]);
if (sessionText.substring(0, textLen) == text) {
text = sessionText;
$this.text(text);
break; // Found it, so we stop
}
}
pageValue.push(text); // If you want it for something
});
I think it's cleaner to just select the elements you care about (in this case the anchor tags) and then use built-in functionality to compare rather than reimplementing a startsWith function.
var sessionValue = ['link1 - Module33', 'link2 - foobar'];
$('.display_links li a').each(function() {
var $this = $(this);
var text = $this.text().trim();
sessionValue.forEach(function(sessionValue) {
if (sessionValue.startsWith(text)) {
$this.text(sessionValue);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="display_links">
<ul id="accounts_links_container">
<li id="accounts_mb_2_id"> link1 </li>
<li id="accounts_mb_11_id"> link2 </li>
</ul>
</div>
The result of $(this).text() is a primitive string, not a reference to the textNode of the element. It doesn't matter if you update pageValue, because it is not related to the original element.
Instead of pushing the strings to an array to process, you can stay inside the $.each() loop and still have access to the elements, which is needed to update the text. Something like this:
$('.display_links li').each(function() {
var $li = $(this);
var liText = $.trim($li.text());
var liLen = liText.length;
for(var w = 0; w < sessionValue.length; w++) {
var sessionLen = $.trim(sessionValue[w]).length;
var newV = sessionValue[w].substring(0, liLen);
if ($.trim(newV) === liText) {
**// UPDATING VALUES AS BELOW**
$li.text(sessionValue[w]);
}
}
});
I am a noob and thought I would take a shot at this.
Here is my approach although the sessionValue array is a bit foggy to me. Is the length undetermined?
I declared var's outside of the loop for better performance so they are not declared over and over.
Iterate through elements passing each value through Compare function and returning the correct value and update immediately after all conditions are satisfied.
var i = 0;
$('.display_links li a').each(function(i) {
$(this).text(Compare($(this).text(), sessionValue[i]));
i++;
});
var Compare;
var update;
Compare = function(val1, val2) {
// Check if val1 does not equal val2 and see if val2 exists(both must be true) then update.
if(!val1 === val2 || val2) {
update = val2
}
return update;
}

Dynamically add new element and change its content

I want to "copy" a certain elements and the change some of the text inside them with a regex.
So far so good: (/w working fiddle - http://jsfiddle.net/8ohzayyt/25/)
$(document).ready(function () {
var divs = $('div');
var patt = /^\d\./;
var match = null;
for (i = 0; i < divs.length; i++) {
match = ($(divs[i]).text().match(patt));
$(divs[i]).text($(divs[i]).text().replace(match[0], "5."));
}
});
HTML
<div>1. peppers</div>
<div>2. eggs</div>
<div>3. pizza</div>
This works exactly the way I want it, but I want to add some of the content dynamically, but when I try to change the content of the copied divs, nothing happens.
Please refer to this fiddle:
http://jsfiddle.net/8ohzayyt/24/
I have put some comments, to be more clear what I want to achieve.
I thing that your problem is that you're not passing an element to your changeLabel function, but just a string.
Look at this solution: http://jsfiddle.net/8ohzayyt/26/
Here is the line I changed to make your code work:
var newContent = $("<hr/><div id='destination'>" + $("#holder").html() + "</div>");
I just wrapped your HTML in $(). this creates an element from the string.
try:
var newContent = $("<hr/><div id='destination'>" + $("#holder").html() + "</div>");
EDIT:
Brief explanation What I've done.
In order to make $(el).find('div'); work changeLabel() needs an element. Instead of passing newContent as a string doing the above will make it pass as an element which will make $(el).find('div'); work.

appendChild() and createElement() Javascript question

When I use appendChild() and createElement() in my code, the subsequent styles for the defined CSS IDs are not applied. Can someone tell me why? Here's my code:
function searchDone(results) {
var result = null;
var parent = document.getElementById('postWrap');
var child = null;
parent.innerHTML = '';
var insertHTML =" ";
//Paginating Results Links
resultNum = results.SearchResponse.Web.Total;
resultNum = resultNum/10;
child = document.createElement('div');
child.id = "paging";
if(results.SearchResponse.Web.Offset != 0){
insertHTML ='<span><a class="jsonp b" href="#" rev="'+(results.SearchResponse.Web.Offset-10)+'"><</a></span>';
}
if(results.SearchResponse.Web.Offset == 0){
insertHTML += '<span>1</span>';
}else{
insertHTML +='<span><a class="jsonp" href="#" rev="0">1</a></span>';
}
for(var i = 1; i <= resultNum; i++){
if((results.SearchResponse.Web.Offset/10) == i){
insertHTML += '<span>'+(i+1)+'</span>';
}else{
insertHTML += '<span><a class="jsonp b" href="#" rev="'+i*10+'">'+(i+1)+'</a></span>';
}
}
if(results.SearchResponse.Web.Total - results.SearchResponse.Web.Offset > 10){
insertHTML += '<span><a class="jsonp b" href="#" rev="'+(results.SearchResponse.Web.Offset+10)+'">></a></span>';
}
child.innerHTML = insertHTML;
parent.appendChild(child);
I then have some other code which processes my search query via API to Bing (only because Google now charges... )
Next, I use the same methods to insert another div:
//Insert Paginating results again
child = null;
child = document.createElement('div');
child.innerHTML = insertHTML;
child.id = "searchResultsPages";
parent.appendChild(child);
Now I'd like to apply some styles to these numbers. However, when I apply a style to searchResultsPage, like
#searchResultsPages{
float: right;
}
I don't get the style being passed on. The curious thing is that if I only insert one of these two elements, everything goes as planned and the style shows up fine. The problem is that I'd like pages displayed at the top and bottom of the search.
Any ideas why this is happening? I think it might have something to do with an element being used twice, but I don't know why this would effect anything if the objects are different.
Thanks.
child.id = "searchResultsPages";
#searchResultsPage{
See anything wrong there? :)
Like an s
IDs should be unique within the page so if you have two elements with id="searchResultsPage" the behaviour can get a bit screwy and the HTML is invalid. Instead, use a class="searchResultsPage" if there will be multiple elements.
The issue of the missing 's' the other commenters point out is also quite important though hopefully that was just a typo in the question.

Filtering the list of friends extracted by Facebook graph api ( more of a JavaScript/Jquery question than Facebook API question)

Hello there JavaScript and Jquery gurus, I am getting and then displaying list of a facebook user's friend list by using the following code:
<script>
function getFriends(){
var theword = '/me/friends';
FB.api(theword, function(response) {
var divInfo = document.getElementById("divInfo");
var friends = response.data;
divInfo.innerHTML += '<h1 id="header">Friends/h1><ul id="list">';
for (var i = 0; i < friends.length; i++) {
divInfo.innerHTML += '<li>'+friends[i].name +'</li>';
}
divInfo.innerHTML += '</ul></div>';
});
}
</script>
graph friends
<div id = divInfo></div>
Now, in my Facebook integrated website, I would eventually like my users to choose their friends and send them gifts/facebook-punch them..or whatever. Therefore, I am trying to implement a simple Jquery filter using this piece of code that manipulates with the DOM
<script>
(function ($) {
// custom css expression for a case-insensitive contains()
jQuery.expr[':'].Contains = function(a,i,m){
return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
function listFilter(header, list) { // header is any element, list is an unordered list
// create and add the filter form to the header
var form = $("<form>").attr({"class":"filterform","action":"#"}),
input = $("<input>").attr({"class":"filterinput","type":"text"});
$(form).append(input).appendTo(header);
$(input)
.change( function () {
var filter = $(this).val();
if(filter) {
// this finds all links in a list that contain the input,
// and hide the ones not containing the input while showing the ones that do
$(list).find("a:not(:Contains(" + filter + "))").parent().slideUp();
$(list).find("a:Contains(" + filter + ")").parent().slideDown();
} else {
$(list).find("li").slideDown();
}
return false;
})
.keyup( function () {
// fire the above change event after every letter
$(this).change();
});
}
//ondomready
$(function () {
listFilter($("#header"), $("#list"));
});
}(jQuery));
</script>
Now, This piece of code works on normal unordered list, but when the list is rendered by JavaScript, it does not. I have a hunch that it has to do something with the innerHTML method. Also, I have tried putting the JQuery filter code within and also right before tag. Neither seemed to work.
If anyone knows how to resolve this issue, please help me out. Also, is there a better way to display the friends list from which users can choose from?
The problem is here:
$(list).find("a:not(:Contains(" + filter + "))").parent().slideUp();
$(list).find("a:Contains(" + filter + ")").parent().slideDown();
Since you're rendering this:
divInfo.innerHTML += '<li>'+friends[i].name +'</li>';
There is no anchor wrapper, the text is directly in the <li> so change the first two lines to look in those elements accordingly, like this:
$(list).find("li:not(:Contains(" + filter + "))").slideUp();
$(list).find("li:Contains(" + filter + ")").slideDown();
You could also make that whole section a bit faster by running your Contains() code only once, making a big pact for long lists, like this:
$(input).bind("change keyup", function () {
var filter = $(this).val();
if(filter) {
var matches = $(list).find("li:Contains(" + filter + ")").slideDown();
$(list).find("li").not(matches).slideUp();
} else {
$(list).find("li").slideDown();
}
});
And to resolve those potential (likely really) innerHTML issues, build your structure by using the DOM, like this:
function getFriends(){
var theword = '/me/friends';
FB.api(theword, function(response) {
var divInfo = $("#divInfo"), friends = response.data;
divInfo.append('<h1 id="header">Friends/h1>');
var list = $('<ul id="list" />');
for (var i = 0; i < friends.length; i++) {
$('<li />', { text: friends[i].name }).appendTo(list);
}
divInfo.append(list);
});
}
By doing it this way you're building your content all at once, the <ul> being a document fragment, then one insertion....this is also better for performance for 2 reasons. 1) You're currently adding invalid HTML with the .innerHTML calls...you should never have an unclosed element at any point, and 2) you're doing 2 DOM manipulations (1 for the header, 1 for the list) after the much faster document fragment creation, not repeated .innerHTML changes.

Populating div with checkboxes

I use this code to determine checkbox width and height:
var chk = $('input[type="checkbox"]:first');
chkWidth = chk.innerWidth()
+ parseInt(chk.css('margin-left').replace('px', ''))
+ parseInt(chk.css('margin-right').replace('px', '')); /*IS there better way instead of px replace?? */
chkHeight = chk.innerHeight()
+ parseInt(chk.css('margin-top').replace('px', ''))
+ parseInt(chk.css('margin-bottom').replace('px', ''));
fieldWidth = gamefield.innerWidth();
fieldHeight = gamefield.innerHeight();
Then i try to fill div with the number of checkboxes that exactly fits given div. In fact i get a lot of checkboxes out of div.
http://dl.dropbox.com/u/3473965/jq/tetris.html
http://dl.dropbox.com/u/3473965/jq/tetris.js
Is there anyway to solve this? Thank you!
leaving other things as such, this makes the difference (on FF3.5):
var cols=Math.floor(fieldWidth/chkWidth);
var rows=Math.floor(fieldHeight/chkHeight);
var html='';
for(var i=0;i<=rows;i++) //if yo use i<rows there is space for one more row
{
for(var j=0;j<cols;j++)
{
html +="<input type='checkbox'/>";
}
}
gamefield.html(html);

Categories

Resources