2
\$\begingroup\$

I have been coding in javascript for almost a year now, and I would like your input on what I could do better. Also, any tips for organizing code a little better? Do you use MVC for every project? Here is my neighborhood map: http://capozzic1.github.io/knockout_map/

Here is the server.js code(express server):

     var Module = (function () {
    'use strict';

    var cors = require('cors');
    var debug = require('debug')('app');
    var express = require('express');
    var http = require('http');
    var bodyParser = require('body-parser');
    var app = express();
    var name = "server";
    var yelpInData = [];

    var port = process.env.PORT || 8080;

    const yelp = require('yelp-fusion');

    //const client = yelp.client(token);
    app.listen(port, function () {
        console.log('Example app listening on port' + port);
    });

    //allow cors
    app.use(cors());
    // create application/json parser
    app.use(bodyParser.json());
    // create application/x-www-form-urlencoded parser
    app.use(bodyParser.urlencoded({
            extended: true
        }));

    //handle post requests
    app.post('/p', function (req, res) {

        req.body.forEach((item) => {
            yelpInData.push(item);
        });

        yelp.accessToken('clientid', 'clienttoken')
        .then(response => {
            const client = yelp.client(response.jsonBody.access_token);

            debug('test');

            var yelpOutData = [];




            yelpInData.forEach(function (item, i) {
                let coords = yelpInData[i].coords.lat + "," + yelpInData[i].coords.lng;
                let name = yelpInData[i].name;

                client.search({
                    term: name,
                    location: coords

                }).then(response => {

                    //name, img url, review count, rating, price, location.display address, is closed,phone
                    yelpOutData.push({
                        name: response.jsonBody.businesses[0].name,
                        img: response.jsonBody.businesses[0].image_url,
                        hours: response.jsonBody.businesses[0].is_closed,
                        revcount: response.jsonBody.businesses[0].review_count,
                        rating: response.jsonBody.businesses[0].rating,
                        price: response.jsonBody.businesses[0].price,
                        location: response.jsonBody.businesses[0].location.display_address.toString(),
                        phone: response.jsonBody.businesses[0].display_phone,
                        url: response.jsonBody.businesses[0].url
                    });


                    if (yelpOutData.length === yelpInData.length) {
                        res.send(yelpOutData);
                        yelpInData = [];
                        yelpOutData = [];

                    } else if (yelpOutData.length > yelpInData.length) {
                        debug('over len');
                    }



                }).catch (e => {
                    console.log(e);
                });
            });




        }).catch (e => {
            console.log(e);
        });


    });

})();

Here is my map.js code that initiates the map:

var Module = (function () {

    var markers = [];
    var contentsBefSort = [];
    var infoWindows = [];
    var contentsNew = [];
    var ready = false;

    //model data
    var locations = [{
            name: 'Le Thai',
            coords: {
                lat: 36.168743,
                lng: -115.139866
            }
        }, {
            name: 'Atomic Liquors',
            coords: {
                lat: 36.166782,
                lng: -115.13551
            }
        }, {
            name: 'The Griffin',
            coords: {
                lat: 36.168785,
                lng: -115.140329
            }
        }, {
            name: 'Pizza Rock',
            coords: {
                lat: 36.17182,
                lng: -115.142304
            }
        }, {
            name: 'The Mob Museum',
            coords: {
                lat: 36.172815,
                lng: -115.141242
            }
        }, {
            name: "Joe Vicari's Andiamo Italian Steakhouse",
            coords: {
                lat: 36.169437,
                lng: -115.142903
            }
        }, {
            name: 'eat.',
            coords: {
                lat: 36.166535,
                lng: -115.139067
            }
        }, {
            name: "Hugo's Cellar",
            coords: {
                lat: 36.169915,
                lng: -115.143861
            }
        }, {
            name: 'Therapy',
            coords: {
                lat: 36.169041,
                lng: -115.139829
            }
        }, {
            name: 'VegeNation',
            coords: {
                lat: 36.167401,
                lng: -115.139453
            }
        }

    ];



    //convert array to JSON
    var jsonStr = JSON.stringify(locations);

    $.ajax({
        url: 'https://gentle-fortress-70127.herokuapp.com/p',
        type: "POST",
        contentType: "application/json", // <====
        data: jsonStr,
        success: function (data) {
            $.each(data, function (i, location) {
                var htmlStr = "";
                var hours = "";
                console.log(location.hours);
                if (location.hours == false) {
                    hours = "Is closed";
                } else {
                    hours = "Is open";
                }

                htmlStr += '<div class ="info">' +
                '<h2 class="name">' + location.name.toString() + '</h2>' +
                '<img class="buspic" src=' + location.img + " alt text='bus pic'" + '/>' +
                '<p class="hours">' + "<b>Open or closed: </b>" + hours + '</p>' +
                '<p class="reviews">' + "<b>Review count: </b>" + location.revcount + '</p>' +
                '<p class="rating">' + "<b>Rating: </b>" + location.rating + '</p>' +
                '<p class="price">' + "<b>Price range: </b>" + location.price + '</p>' +
                '<p class="location">' + "<b>Address: </b>" + location.location + '</p>' +
                '<p class="phone">' + "<b>Phone: </b>" + location.phone + '</p>' +
                '<a href="' + location.url + '">' + 'See more on yelp' + '</a>' +
                '</div>';

                contentsBefSort.push(htmlStr);

            });

            sortArr(contentsBefSort);



            if (ready) {
                weatherData(function (data) {
                    console.log(data);
                    var city = data.name;
                    var currWeather = data.weather[0].description;
                    var pic = 'http://openweathermap.org/img/w/' + data.weather[0].icon + '.png';
                    var currTemp = data.main.temp;
                    var tempHi = data.main.temp_max;
                    var humid = data.main.humidity;

                    var div = '<div class="weatherIn"></div>';
                    $('body').append(div);

                    $('.weatherIn').append(
                        '<h2>Weather for Downtown ' + city + '</h2>' +
                        '<p>Description: ' + currWeather + '</p>' +
                        '<img src="' + pic + '" alt="Pic here" />' +
                        '<p>Current temperature: ' + currTemp + '&#8457' + '</p>' +
                        '<p>The high for today is ' + tempHi + '&#8457' + '</p>' +
                        '<p>Humidity: ' + humid + '</p>');

                });
                initMap();

            }
        }
    });
    function sortList() {

        $('.search').keyup(function (e) {
            var val = $('.search').val();
            var list = $('.btns li');
            if (val != "") {
                $(list).css("display", "none");
                $(list).each(function (i) {
                    var h2text = $(this).find('h2').text();

                    if (h2text.includes(val)) {

                        $(this).css("display", "block");

                    }
                });
            } else {
                $(list).css("display", "block");
            }

        });

    };

    function sortArr(arr) {

        for (var j = 0; j < locations.length; j++) {

            for (var i = 0; i < arr.length; i++) {

                if (arr[i].indexOf(locations[j].name) > -1 || arr[i].indexOf(locations[j].name) == 0) {



                    contentsNew[j] = arr[i];



                }
            }
        }

        ready = true;
    };

    function weatherData(callback) {
        var weather = 'https://api.openweathermap.org/data/2.5/weather?lat=36.168743&lon=-115.139866&units=imperial&APPID=derp';

        $.ajax({
            dataType: "jsonp",
            url: weather,
            success: callback
        });
    };

    var initMap = function () {

        $(' <input type="text" placeholder="Search here" class="search" value="" />').insertBefore('.btns');

        if (ready) {
            var map;
            map = new google.maps.Map(document.getElementById('map'), {
                    center: {
                        lat: 36.168743,
                        lng: -115.139866
                    },
                    zoom: 15
                });

            for (let i = 0; i < locations.length; i++) {

                //make markers
                markers[i] = new google.maps.Marker({
                        position: new google.maps.LatLng(locations[i].coords.lat, locations[i].coords.lng),
                        map: map,
                        title: locations[i].name
                    });

                markers[i].index = i; //add index

                $('.btns').append('<li>' + contentsNew[i] + '</li>');


                var infoWindow = new google.maps.InfoWindow();

                infoWindow.setOptions({
                    maxWidth: 250
                });

                google.maps.event.addListener(markers[i], 'click', function () {
                    (this.index);
                    infoWindow.setContent([contentsNew[i]].toString());
                    infoWindow.open(map, markers[this.index]);
                    map.setZoom(16);
                    map.panTo(markers[this.index].getPosition());
                });
                var list = $('.btns li');
                //console.log(list[i]);
                google.maps.event.addDomListener(list[i], 'click', function () {
                    infoWindow.setContent([contentsNew[i]].toString());
                    map.setZoom(16);
                    infoWindow.open(map, markers[i]);
                    map.panTo(markers[i].getPosition());
                });

                var mapCenter = new google.maps.LatLng(36.168743, -115.139866);

                google.maps.event.addListener(infoWindow, 'closeclick', function () {
                    map.setCenter(mapCenter);
                    map.setZoom(15);
                });
            };
        };

        sortList();

    };

    return {
        initMap: initMap
    };
})();

A somewhat unrelated career question I have is, if I'm trying to become a front end developer in a year, would it benefit me to learn a backend language like php/python/c#?

\$\endgroup\$
1
\$\begingroup\$

As general note, your functions are doing too much, search Robert Martin aka Uncle Bob advices on clean code and single responsibility.

Use pure functions to prepare your request objects and the more convenient wrappers (fetch or request-promise on the server) than $.ajax. You can easily test those functions without ever touching the ajax.

Assembling HTML inside JS is a big anti-pattern, especially concatenating strings. At worst, you should assemble arrays of strings and .join into strings at the end with single operation.

for (var j = 0; j < locations.length; ...

is better to write as

for (var j = 0, l = locations.length; j < l; ...

because right now your .length method runs on every iteration. Even better to use more compact functional way like

const sortArr = arr => arr.forEach((entry, index) => ...)

or even better avoid side-effects mutating variables outside your function by making them instead return all the necessary data:

const sortArr = arr => { 
    let contentsNew = [];
       ... 
    return contentsNew;
}

Again, pure functions without side-effects are easier to test in isolation. Use the .map and .filter methods on arrays for shorter and simpler code and libraries such as Ramda (my favourite) or Lodash.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.