HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

JSON call for stock info using YQL

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
infoyqlstockcallforusingjson

Problem

I got this code working but it feels clunky. I am wondering if there is a way I can improve it.

(I'm intermingling JavaScript and jQuery). I'm using jquery-1.11.1.min.js hosted on code.jquery.com.

Here is the jsFiddle

JS:


$('#indices > div').each(function () { 
var url = "http://query.yahooapis.com/v1/public/yql";
var $this = $(this);
var symbol = $this.attr('id');
var data = encodeURIComponent("select * from yahoo.finance.quotes where symbol in ('" + symbol + "')");

$.getJSON(url, 'q=' + data + "&format=json&diagnostics=true&env=http://datatables.org/alltables.env")
    .done(function (data) {

        $this.children('#aname').text(data.query.results.quote.Symbol);
        $this.children('#aresult').text(data.query.results.quote.LastTradePriceOnly);

        $this.children('#apercentchg').text(data.query.results.quote.PercentChange);
        $this.children('#adollarchg').text(data.query.results.quote.Change);
        if (data.query.results.quote.PercentChange.indexOf("+") != -1) {
            $this.addClass("divgreen");
            $this.children('#apercentchg').className = "greenText";
        } else {
            $this.addClass("divred");
            $this.children('#apercentchg').className = "redText";
        }
    });
});


HTML:


    
        S&P 500 
          
    
    
        Nasdaq 100 
          
    
    
        SPDR Gold 
          
    
    
        iShares Silver 
          
    
    
        Nikkei 225 
          
    
    
        FTSE 
          
    


CSS:


div.indices {
    font: 12px/19px Helvetica, Arial, sans-serif;
    width: 825px;
    margin: 0 auto;
}
.divgreen {
    color: #000;
    float: left;
    background-color: #70DB70;
    border-right: 3px solid #FFF;
    padding: 3px;
}
.divred {
    color: #000;
    float: left;
    background-color: #f7cdc2;
    border-right: 3px solid #FFF;
    padding: 3px;
}


Update Here is the final product of the great suggestions below and some additional changes. I al

Solution


  • Don't repeat element IDs. What you want is a data-* attribute, e.g. data-property. Or you could use class names, since those can repeat and you'll want to style things anyway. Of course, you could also build your elements as needed.



  • Use CSS classes properly. If you've set the containing DIV's class, you just need to write your CSS to automatically style its descendants properly, instead of setting a class like redtext. While you're at it, don't use an element name in your class names. If you want target a specific tag a selector like div.green is what you need, in which case the class name would just be green. However, green is problematic too; you're not saying it should be green, you're saying that that index/stock is up or rising. So name your classes that; i.e. name them something semantically appropriate.



  • It'd be simpler to first collect all the symbol names, and then query Yahoo once for all of them, instead of firing off queries one at a time.



  • Use $.getJSON's ability to accept a data object, rather than manually creating a query string



For instance, you could use this HTML (repeat as needed, unless you want to simply build it in JS):


  S&P 500
  
  


and this CSS:

.symbol { /* basic styling */ }

.symbol.up { /* styling for a symbol that's "up" */ }
.symbol.up .change { /* styling for the change span */ }

.symbol.down { /* styling for a symbol that's "down" */ }
.symbol.down .change { /* styling for the change span */ }


As for the JavaScript

var elements, symbols, query;

// get the elements
elements = $(".symbol");

// get the symbols and join them to a comma-separated string
symbols = elements.map(function () {
    var symbol = $(this).data("symbol")
    return "'"+symbol+"'";
}).toArray().join(",");

// get the quotes
$.getJSON("http://query.yahooapis.com/v1/public/yql", {
    format: "json",
    diagnostics: "true",
    env: "http://datatables.org/alltables.env",
    q: "select * from yahoo.finance.quotes where symbol in (" + symbols + ")"
}, function (data, xhr, status) {
    // TODO: sanity checking of the data
    data.query.results.quote.forEach(function (quote) {
        var element = elements.filter("[data-symbol='"+quote.Symbol+"']:first");
        if(/^\+/.test(quote.PercentChange)) {
            element.addClass("up");
        } else {
            element.addClass("down");
        }
        element.children("[data-property]").each(function () {
            var child = $(this),
                prop = child.data("property");
            child.text(quote[prop]);
        });
    });
});


Here's a jsfiddle

Of course, a much simpler approach would to be build elements as needed. Keep the CSS but remove all the HTML (except the indices div, just so we have a place to put stuff) in favor of letting your JS do the work of setting it all up.

var symbols = ['^GSPC', '^NDX', 'GLD', 'SLV', '^N225', '^FTSE'],
    properties = [
        { classname: 'name', property: 'Name' },
        { classname: 'result', property: 'LastTradePriceOnly' },
        { classname: 'change', property: 'Change' }
    ];

function buildElement(quote) {
    var container = $("").addClass("symbol");
    properties.forEach(function (prop) {
        var child = $("").addClass(prop.classname);
        child.text(quote[prop.property]);
        container.append(child);
    });
    if(/^\+/.test(quote.PercentChange)) {
        container.addClass("up");
    } else {
        container.addClass("down");
    }
    return container;
}

$.getJSON("http://query.yahooapis.com/v1/public/yql", {
    format: "json",
    diagnostics: "true",
    env: "http://datatables.org/alltables.env",
    q: "select * from yahoo.finance.quotes where symbol in ('" + symbols.join("','") + "')"
}, function (data, xhr, status) {
    // do some sanity checking of the data here
    var elements = data.query.results.quote.map(buildElement);
    $("#indices").append(elements);
});


Here's a jsfiddle of that.

Code Snippets

<div class="symbol" data-symbol="^GSPC">
  <span class="name">S&amp;P 500</span>
  <span class="result" data-property="LastTradePriceOnly"></span>
  <span class="change" data-property="Change"></span>
</div>
.symbol { /* basic styling */ }

.symbol.up { /* styling for a symbol that's "up" */ }
.symbol.up .change { /* styling for the change span */ }

.symbol.down { /* styling for a symbol that's "down" */ }
.symbol.down .change { /* styling for the change span */ }
var elements, symbols, query;

// get the elements
elements = $(".symbol");

// get the symbols and join them to a comma-separated string
symbols = elements.map(function () {
    var symbol = $(this).data("symbol")
    return "'"+symbol+"'";
}).toArray().join(",");

// get the quotes
$.getJSON("http://query.yahooapis.com/v1/public/yql", {
    format: "json",
    diagnostics: "true",
    env: "http://datatables.org/alltables.env",
    q: "select * from yahoo.finance.quotes where symbol in (" + symbols + ")"
}, function (data, xhr, status) {
    // TODO: sanity checking of the data
    data.query.results.quote.forEach(function (quote) {
        var element = elements.filter("[data-symbol='"+quote.Symbol+"']:first");
        if(/^\+/.test(quote.PercentChange)) {
            element.addClass("up");
        } else {
            element.addClass("down");
        }
        element.children("[data-property]").each(function () {
            var child = $(this),
                prop = child.data("property");
            child.text(quote[prop]);
        });
    });
});
var symbols = ['^GSPC', '^NDX', 'GLD', 'SLV', '^N225', '^FTSE'],
    properties = [
        { classname: 'name', property: 'Name' },
        { classname: 'result', property: 'LastTradePriceOnly' },
        { classname: 'change', property: 'Change' }
    ];

function buildElement(quote) {
    var container = $("<div></div>").addClass("symbol");
    properties.forEach(function (prop) {
        var child = $("<span></span>").addClass(prop.classname);
        child.text(quote[prop.property]);
        container.append(child);
    });
    if(/^\+/.test(quote.PercentChange)) {
        container.addClass("up");
    } else {
        container.addClass("down");
    }
    return container;
}

$.getJSON("http://query.yahooapis.com/v1/public/yql", {
    format: "json",
    diagnostics: "true",
    env: "http://datatables.org/alltables.env",
    q: "select * from yahoo.finance.quotes where symbol in ('" + symbols.join("','") + "')"
}, function (data, xhr, status) {
    // do some sanity checking of the data here
    var elements = data.query.results.quote.map(buildElement);
    $("#indices").append(elements);
});

Context

StackExchange Code Review Q#51162, answer score: 7

Revisions (0)

No revisions yet.