Shorten function in Javascript / Jquery - javascript

LF way to short my js/jquery function:
$.ajax({ // Start ajax post
..........
success: function (data) { // on Success statment start
..........
//1. Part
$('var#address').text(data.address);
$('var#telephone').text(data.telephone);
$('var#mobile').text(data.mobile);
$('var#fax').text(data.fax);
$('var#email').text(data.email);
$('var#webpage').text(data.webpage);
//2. Part
if (!data.address){ $('p#address').hide(); } else { $('p#address').show(); };
if (!data.telephone){ $('p#telephone').hide(); } else { $('p#telephone').show(); };
if (!data.mobile){ $('p#mobile').hide(); } else { $('p#mobile').show(); };
if (!data.fax){ $('p#fax').hide(); } else { $('p#fax').show(); };
if (!data.email){ $('p#email').hide(); } else { $('p#email').show(); };
if (!data.webpage){ $('p#webpage').hide(); } else { $('p#webpage').show(); };
}, End Ajax post success statement
Here is my html:
<p id="address">Address:<var id="address">Test Street 999 2324233</var></p>
<p id="telephone">Telephone:<var id="telephone">+1 0000009</var></p>
<p id="mobile">Mobile:<var id="mobile">+1 0000009</var></p>
<p id="email">E-mail:<var id="email">info#example</var></p>
<p id="webpage">Web Page:<var id="webpage">www.example.com</var>/p>
How can we reduce the number of selector*(1. part)* and else if the amount (2. part)?

Assuming your object's property names exactly match the spelling of your element ids you can do this:
for (var k in data) {
$('var#' + k).text(data[k]);
$('p#' + k).toggle(!!data[k]);
}
...because .toggle() accepts a boolean to say whether to show or hide. Any properties that don't have a matching element id would have no effect.
Note: your html is invalid if you have multiple elements with the same ids, but it will still work because your selectors specify the tag and id. Still, it might be tidier to just remove the ids from the var elements:
<p id="address">Address:<var>Test Street 999 2324233</var></p>
<!-- etc. -->
With this JS:
$('#' + k).toggle(!!data[k]).find('var').text(data[k]);
And then adding some code to hide any elements that aren't in the returned data object:
$('var').parent('p').hide();
...and putting it all together:
$.ajax({
// other ajax params here
success : function(data) {
$('var').parent('p').hide();
for (var k in data) {
$('#' + k).toggle(!!data[k]).find('var').text(data[k]);
}
}
});
Demo: http://jsfiddle.net/z98cw/1/

["address", "telephone", "mobile", "fax", "email", "webpage"].map(
function(key) {
if (data.hasOwnProperty(key) && !!data[key]) {
$('p#' + key).show();
} else {
$('p#' + key).hide();
}
});
But you should not.

As long as the properties of the object match the id attributes of the p tags you can iterate through the object using the property name as a selector. Also since id attributes are unique, refrain from prefixing the selector with var it is unnecessary.
var data = {
address: "address",
telephone: "telephone",
mobile: "mobile",
fax: "fax",
email: "email",
webpage: "webpage"
};
for(x in data){
var elem = $("#" + x);
if(elem.length == 1){
elem.text(data[x]);
}
}
JS Fiddle: http://jsfiddle.net/3uhx6/

This is what templating systems are created for.
If you insist on using jQuery there is a jQuery plugin: https://github.com/codepb/jquery-template
More:
What Javascript Template Engines you recommend?

I would use javascript templates for this (I've shortened the example a quite a bit, but you should get the gist).
First the template, I love Underscore.js for this so I gonna go ahead and use that.
<% if data.address %>
<p id="address">Address: {%= Test Street 999 2324233 %}</p>
to compile this inside your success function
success: function(data) {
//assuming data is a json that looks like this {'address':'my street'}
var template = _.template(path_to_your_template, data);
$('var#addresscontainer').html(template);
}

Thanks for birukaze and nnnnnn:
With your advice came function;) :
for (var key in data) {
if (data.hasOwnProperty(key) && !!data[key]) {
$('p#' + key).show().find('var').text(data[key]);
} else {
$('p#' + key).hide();
}
};
Now i can avoid for selector with var.

Related

How to loop through HTML elements and populate a Json-object?

I'm looping through all the html tags in an html-file, checking if those tags match conditions, and trying to compose a JSON-object of a following schema:
[
{ title: 'abc', date: '10.10.10', body: ' P tags here', href: '' },
{ title: 'abc', date: '10.10.10', body: ' P tags here', href: '' },
{ title: 'abc', date: '10.10.10', body: ' P tags here', href: '' }
]
But I'd like to create the new entry only for elements, classed "header", all the other elements have to be added to earlier created entry. How do I achieve that?
Current code:
$('*').each((index, element) => {
if ( $(element).hasClass( "header" ) ) {
jsonObject.push({
title: $(element).text()
});
};
if( $(element).hasClass( "date" )) {
jsonObject.push({
date: $(element).text()
});
}
//links.push($(element))
});
console.log(jsonObject)
Result is:
{
title: 'TestA'
},
{ date: '10.10.10' },
{
title: 'TestB'
},
{ date: '10.10.11' }
I'd like it to be at this stage something like:
{
title: 'TestA'
,
date: '10.10.10' },
{
title: 'TestB'
,
date: '10.10.11' }
UPD:
Here's the example of HTML file:
<h1 class="header">H1_Header</h1>
<h2 class="date">Date</h2>
<p>A.</p>
<p>B.</p>
<p>С.</p>
<p>D.</p>
<a class="source">http://</a>
<h1 class="header">H1_Header2</h1>
<h2 class="date">Date2</h2>
<p>A2.</p>
<p>B2.</p>
<p>С2.</p>
<p>D2.</p>
<a class="source">http://2</a>
Thank you for your time!
Based on your example Html, it appears everything you are trying to collect is in a linear order, so you get a title, date, body and link then a new header with the associated items you want to collect, since this appears to not have the complication of having things being ordered in a non-linear fasion, you could do something like the following:
let jsonObject = null;
let newObject = false;
let appendParagraph = false;
let jObjects = [];
$('*').each((index, element) => {
if ($(element).hasClass("header")) {
//If newObject is true, push object into array
if(newObject)
jObjects.push(jsonObject);
//Reset the json object variable to an empty object
jsonObject = {};
//Reset the paragraph append boolean
appendParagraph = false;
//Set the header property
jsonObject.header = $(element).text();
//Set the boolean so on the next encounter of header tag the jsobObject is pushed into the array
newObject = true;
};
if( $(element).hasClass( "date" )) {
jsonObject.date = $(element).text();
}
if( $(element).prop("tagName") === "P") {
//If you are storing paragraph as one string value
//Otherwise switch the body var to an array and push instead of append
if(!appendParagraph){ //Use boolean to know if this is the first p element of object
jsonObject.body = $(element).text();
appendParagraph = true; //Set boolean to true to append on next p and subsequent p elements
} else {
jsonObject.body += (", " + $(element).text()); //append to the body
}
}
//Add the href property
if( $(element).hasClass("source")) {
//edit to do what you wanted here, based on your comment:
jsonObject.link = $(element).next().html();
//jsonObject.href= $(element).attr('href');
}
});
//Push final object into array
jObjects.push(jsonObject);
console.log(jObjects);
Here is a jsfiddle for this: https://jsfiddle.net/Lyojx85e/
I can't get the text of the anchor tags on the fiddle (I believe because nested anchor tags are not valid and will be parsed as seperate anchor tags by the browser), but the code provided should work in a real world example. If .text() doesn't work you can switch it to .html() on the link, I was confused on what you are trying to get on this one, so I updated the answer to get the href attribute of the link as it appears that is what you want. The thing is that the anchor with the class doesn't have an href attribute, so I'll leave it to you to fix that part for yourself, but this answer should give you what you need.
$('*').each((index, element) => {
var obj = {};
if ( $(element).hasClass( "header" ) ) {
obj.title = $(element).text();
};
if( $(element).hasClass( "date" )) {
obj.date = $(element).text()
}
jsonObject.push(obj);
});
I don't know about jQuery, but with JavaScript you can do with something like this.
const arr = [];
document.querySelectorAll("li").forEach((elem) => {
const obj = {};
const title = elem.querySelector("h2");
const date = elem.querySelector("date");
if (title) obj["title"] = title.textContent;
if (date) obj["date"] = date.textContent;
arr.push(obj);
});
console.log(arr);
<ul>
<li>
<h2>A</h2>
<date>1</date>
</li>
<li>
<h2>B</h2>
</li>
<li>
<date>3</date>
</li>
</ul>
Always use map for things like this. This should look something like:
let objects = $('.header').get().map(el => {
return {
date: $(el).attr('date'),
title: $(el).attr('title'),
}
})

javascript to filter unwanted data

I am new to angular js. I have a link http://www.bursamalaysia.com/searchbox_data.json that I want to get a list of name and id.
I able to get the list from a link in json but I need to filter unwanted items in the list. If the id is more than 4 digits, then remove full_name,name, short_name and id. example: if id:123456 , it need to be filter out, together with name,short name.
app.js
abc: {
name: "Momo",
value: "kls",
long: "KLSE",
searchRef: KLSE_SEARCH_REF,
searchRefURL: "http://www.bursamalaysia.com/searchbox_data.json",
},
details.js
$ionicLoading.show();
if ($scope.currentMarket == "abc"){
$webServicesFactory.getNotParsed($marketProvider[$scope.currentMarket].searchRefURL).then(function success(response){
response = JSON.parse(response);
for (var i = 0; i < response[0].length; i++){
$scope.searchRef.push({
name: response[0][i].name || response[0][i].full_name,
symbol: response[0][i].short_name,
code: response[0][i].id,
market: $marketProvider[$scope.currentMarket].long
});
}
console.info($scope.searchRef);
$ionicLoading.hide();
});
}
html
<div class="list">
<div class="item" ng-repeat="item in searchItems" ng-click="openDetail(item)">
<p>{{item.symbol}} - {{item.name}}</p>
<p>{{currentMarket | uppercase}}</p>
</div>
</div>
You could go with Array.prototype.filter and Array.prototype.map, which is quite elegant.
$ionicLoading.show();
if($scope.currentMarket == "abc") {
$webServicesFactory.getNotParsed($marketProvider[$scope.currentMarket].searchRefURL).then(
function success(response) {
$scope.searchRef = JSON.parse(response)[0].filter(function(itm) {
// whatever you want to filter should pass this condition
return itm.id.toString().length <= 3;
}).map(function(itm) {
// for each item, transform to this
return {
name: itm.name || itm.full_name,
symbol: itm.short_name,
code: itm.id,
market: $marketProvider[$scope.currentMarket].long
};
});
$ionicLoading.hide();
}
);
}
Make sure to handle any errors and to make your code defensive.
if you need filter more than 4 digit id values , then you can restrict with simple condition if(response[0][i].id <= 999)
example below:
for(var i=0; i<response[0].length; i+=1){
if(response[0][i].id.toString().length <= 3 ) {
$scope.searchRef.push(
{
name: response[0][i].name || response[0][i].full_name,
symbol: response[0][i].short_name,
code: response[0][i].id,
market: $marketProvider[$scope.currentMarket].long
}
);
}
}

DOM not updating on GET request + data-attributes

Issue: Upon updating the src of images, retrieved via GET request, the DOM never updates but their new values show in console.
Suspected Cause: I think there is some conflict with using data-attributes, but using attr() instead of data() does not seem to remedy.
HTML to be updated:
<div class="data-block">
<img data-item="hp-logo" />
<img data-item="hp-banner" />
</div>
GET Request:
if(promoid != null) {
$.get({
url: '/snippets/data.html',
cache: false
}).then(function(data){
var tempData = $('<output>').append($.parseHTML(data)).find('.data[data-promo-id="' + promoid + '"]');
myContent = tempData.html();
dataItems = $('.data-block').html();
//console.log('Data Items On Page: ', dataItems);
$(dataItems).each(function (index, value) {
if( $(this).is('[data-item]')) {
//console.log('Data Items With Attribute: ', this);
dataItemLookup = $(this).attr('data-item');
//console.log('Data Item Lookup Value: ', dataItemLookup);
$(myContent).each(function (index, value) {
//console.log('Retrieved Items Checking Against: ', this);
if ( $(this).attr('data-alias') == lastalias ) {
//console.log('Retrieved Items Match Alias: ', this);
if ($(this).attr('data-item') == dataItemLookup) {
//console.log('Retrieved Item Match', this);
dataImageDesktop = $(this).attr('data-image-desktop');
//console.log('Value to be Passed to Data Item: ', dataImageDesktop);
} else {
// Do nothing
}
} else {
// Do nothing
}
});
$(this).attr('src', dataImageDesktop);
console.log(this);
}
});
});
}
data.html:
<div class="data-container">
<div class="data" data-promo-id="11202016">
<div data-alias="test.html" data-item="hp-logo" data-image-desktop="http://placehold.it/250x150"></div>
<div data-alias="test.html" data-item="hp-banner" data-image-desktop="http://placehold.it/350x250"></div>
<div data-alias="not-test.html" data-item="hp-spot" data-image-desktop="http://placehold.it/450x350"></div>
</div>
</div>
Not sure how to proceed in troubleshooting this issue. Everything works as expected, except the DOM updating. Ideas?
Using html() on an element will get you the innerHTML of the object, which is a string. As such using it inside $() later will cause jQuery to create new elements that are not attached to the DOM. If all you are after is to select elements and modify them, simply use the $(selector) and modify it. Do not use html() and wrap the results with $().
Instead of $(selector).attr('data-name') try using $(selector).data('name') as shown in the jQuery.data() documentation.

how to parse this xml in jquery to get an attribute?

I need to parse the following example XML in jquery, to get the attribute "V"
XML file:
<RES>
<R N="1">
<MT N="myMeta1" V="myMeta1Value"/>
<MT N="myMeta2" V="myMeta2Value"/>
<MT N="myMeta2" V="myMeta2Value"/>
</R>
</RES>
And my javascript is the following:
function(data){
$(data).find('R').each(function(){
var $result = $(this);
$result.find('MT').each(function(_mt) {
console.log($(_mt).attr("V") );
});
});
}
I get undefineds, what am I doing wrong?
The first argument to .each callback is the index, the second one is the value. You can also use this:
$result.find('MT').each(function() {
console.log($(this).attr("V") );
});
Or:
$result.find('MT').each(function( index, _mt ) {
console.log($(_mt).attr("V") );
});
You are using index as an element in each. As first parameter is index pass two parameter in each and use the second to get the element.
function(data){
$(data).find('R').each(function(){
var $result = $(this);
$result.find('MT').each(function(_mt, obj) {
console.log($(obj).attr("V") );
});
});
}

Suggest any Good mustache document

Suggest me any good mustache doc. Also i want to know in a mushtach loop how do i get the count or the loop no. I mean how can i do a for loop in mustache.
In the below code i wish to change the id in every loop
<script src="http://github.com/janl/mustache.js/raw/master/mustache.js"></script>
<script>
var data, template, html;
data = {
name : "Some Tuts+ Sites",
big: ["Nettuts+", "Psdtuts+", "Mobiletuts+"],
url : function () {
return function (text, render) {
text = render(text);
var url = text.trim().toLowerCase().split('tuts+')[0] + '.tutsplus.com';
return '' + text + '';
}
}
};
template = '<h1> {{name}} </h1><ul> {{#big}}<li id="no"> {{#url}} {{.}} {{/url}} </li> {{/big}} </ul>';
html = Mustache.to_html(template, data);
document.write(html)
</script>
<body></body>
You can't get at the array index in Mustache, Mustache is deliberately simple and wants you to do all the work when you set up your data.
However, you can tweak your data to include the indices:
data = {
//...
big: [
{ i: 0, v: "Nettuts+" },
{ i: 1, v: "Psdtuts+" },
{ i: 2, v: "Mobiletuts+" }
],
//...
};
and then adjust your template to use {{i}} in the id attributes and {{v}} instead of {{.}} for the text:
template = '<h1> {{name}} </h1><ul> {{#big}}<li id="no-{{i}}"> {{#url}} {{v}} {{/url}} </li> {{/big}} </ul>';
And as an aside, you probably want to include a scheme in your url:
url : function () {
return function (text, render) {
text = render(text);
var url = text.trim().toLowerCase().split('tuts+')[0] + '.tutsplus.com';
return '' + text + '';
//---------------^^^^^^^
}
}
Demo: http://jsfiddle.net/ambiguous/SFXGG/
Expanding on #mu's answer, you could also keep an index in the data object and have the template refer to it and the function increment it. So you wouldn't need to add i to each item.
see demo : http://jsfiddle.net/5vsZ2/

Categories