Javascript method for getting data based on ID in database table - javascript

I'm building an app with many different datasets. Locations, customers, ratings etc...
Throughout the app there are popups and dynamically filled modules, dropdowns etc... At the moment my method is to attach "data-id" as an attribute to any buttons that create dynamic content then run ajax functions using the attribute to get content for the popup.
I'm assuming this is the correct thing to do for large modules that require a lot of dynamic data, but take the below example.
I have a list of locations, when the user clicks (add link) I'd like the popup module to have the title 'Adding link to [location name]'. Would I really need to create an ajax function simply to fill in the name of the location from the database? I could get it from the DOM but that seems silly because most of the popups require data that isn't in the dom.
Basically, my question is; What is the easiest way to get basic data from the database in javascript?
Here's an example of what I have for a whole bunch of buttons with various modules and titles:
$('body').on('click','.add_board_to_loc',function(){
var id = $(this).attr('data-id');
let getLocation = function(id){
$.ajax({
type: 'POST',
url: 'includes/ajax.php',
data: {
action: 'getLocation',
loc_id: id
},
success: function(data){
$('#add_link_modal_title').text(data['location_name']);
}
});
}
$('#addBoardModal').modal('show');
});

I would split this code into several layers.
One layer can be a transport layer. On transport layer you make ajax request and process errors.
The next layer can be a general layer, here you pass params as table, where statmets and so on. Anyone will be able to access this data through api so be carful with permissions.
And the last layer can be Buisness layer where you request things like: get Location.

Related

Use the same data for multiple tables with tabulator

I'm using jQuery and tabulator to create a fairly simple webpage showing the progress of various live events. I have three table elements on the page showing events in different states. Broadly speaking I have a table for events that are 'Live', 'Finished' and 'Upcoming'.
The tabulator code for each table looks a bit like this:
var eventTable = {
layout:"fitColumns",
columns:[
{title:"Event ID", field:"eventID"},
{title:"Event name", field:"eventName"},
{title:"Event status", field:"eventStatus"}
]
};
I can then generate and populate the tables using data retrieved from the server using an AJAX call:
$('#live-events-table').tabulator(eventTable);
$('#live-events-table').tabulator("setData", "/cgi-bin/getevents.py");
$('#live-events-table').tabulator("setFilter", "status", "in", ["intermission", "mid-event"]);
Then similar code for the finished and upcoming tables.
This creates three requests for getevents.py every time the page is updated. This is undesirable because the data is pulled from another API and I want to avoid sending multiple identical requests. Also, there's a (small) chance the data could change between requests.
Is there a way of using the same data to populate all three tables?
Learnt something today. Never heard of Tabulator. I've been using DataTables for this sort of advanced tabular layout in the form of a jQuery plugin. Tabulator looks promising. Will have to explore more in the future.
In the docs I see Tabulator - Set Table Data, lots of alternative options available to set the data.
Hope I am understanding the problem correctly.
My thoughts/flow for tacking this problem would be:
Assuming your doing this already: Prep server side (getevents.py) needs to return all 'Live', 'Finished' and 'Upcoming' rows in JSON together in 1 response. How do I make a JSON object with multiple arrays?.
Client side on doc ready(), makes a jQuery ajax call to fetch this data before 3 x tabulators are built/called.
You can use a loading indicator. So the client sees something is happening in the 3 x before replaced by jQuery tabulator once the data is returned and you built with tabulator.
In the ajax success callback function you can iterate over the returned json object (containing the 3 x eventTypes). You might have to JSON.parse() if you store it in a JavaScript variable to iterate over.
Now get your specific array of event types nested objects arrays/json.
Then call your tabulator creation methods using the setData pointing to each specific JavaScript array containing the relevant data.
Not sure if this falls under "premature optimization", but I would proceed as the problem itself is rather fun to solve, but you know the requirements/needs better than I.
Good luck.
I fixed this fairly simply, using suggestions from #RoryGS.
Define the table options in a variable, as before:
var eventTable = {
layout:"fitColumns",
columns:[
{title:"Event ID", field:"eventID"},
{title:"Event name", field:"eventName"},
{title:"Event status", field:"eventStatus"}
]
};
Then make a jQuery ajax call to fetch the data, and build the table(s) in the success option of the function:
$(function() {
$.ajax({
dataType: "json",
url: "/cgi-bin/getevents.py",
success: function(data, status){
$('#live-events-table').tabulator(eventTable);
$('#finished-events-table').tabulator(eventTable);
$('#live-events-table').tabulator("setData", data);
$('#live-events-table').tabulator("setFilter", "status", "in", ["intermission", "mid-event"]);
$('#finished-events-table').tabulator("setData", data);
$('#finished-events-table').tabulator("setFilter", "status", "in", ["post-event"]);
}
})})
It seems to be necessary to set the data individually for each table. I would like to specify the data in the constructor, but this doesn't seem to work. I will continue to try to refine this.
If you are getting the data from a URL you can pass it into the ajaxURL property in the table constructor and tabulator will make the request for you:
$("#example-table").tabulator({
ajaxURL:"/cgi-bin/getevents.pyw", //ajax URL
columns:[...] //define columns etc
});

Showing single data field via Google Analytics API

I'm having trouble displaying only a single data field via the Google Analytics API.
For example, how would I display the number of users yesterday? Or the number of users in the past week?
I'm assuming "gapi.analytics.report.Data" is the right constructor. I've tried following the "Data" code in Google's Built-in Components Reference but nothing displays on the front-end.
For the "DataChart" code, there's a "container" option that references the HTML element in the DOM that will correctly display the chart.
This "container" option is missing in "Data" - so how do I display a single data field?
EDIT: Here's the code I'm working with.
You can see a pastebin of my code here: https://pastebin.com/M6U0Bd8B
There's also a live staging version of the site here: http://madebychris.ca/dashboard2.html
The first four section ids are all displaying properly but nothing's showing up for the final <p class ="report">
If you are trying to access the raw data numbers, you can just access the response object:
// Set up the request
var report = new gapi.analytics.report.Data({
query: {
ids: 'ga:XXXX',
metrics: 'ga:sessions',
dimensions: 'ga:city'
}
});
// Define what to do with the response data.
report.on('success', function(response) {
console.log(response);
});
// Run the report
report.execute();
For example, the total's for the metrics is response.totalsForAllResults and the rows for each dimension are held in response.rows
You need to select what you want to do with the variables on the report.on("success", function(response){ function. For example:
report.on('success', function(response) {
$("body > main > div > section:nth-child(4) > h2")[0].innerText =
response.totalsForAllResults["ga:sessions"]
});
report.execute();
Note: You should be able to test on the embedded API demo. Copying and pasting the initial code with the console.log should help show what is going on.

Too much JSON crashes browser :(

I have an ajax country/city selector. When I select United States the browser crashes. Doh!
I have a dropdown list of countries. When I select a country a jQuery ajax call is run which gets a JSON response of cities belonging to that country.
I should have seen it coming when I had to increase my allowed memory during execution. Here's the JSON response from selecting the UK.
{"5947":"Aberdeen","12838":"Aberystwyth","15707":"Aldershot","18575":"Alsagers Bank","18682":"Altrincham","4863":"Andover","41802":"AOL","6471":"Armagh","18945":"Ascot","4864":"Ashby-de-la-Zouch","4865":"Ashford","5948":"Aviemore","12985":"Aylesbury","12281":"Ballymena","14446":"Banbury","12445":"Bangor","13631":"Barking","4866":"Barnet","17004":"Barnsley","16423":"Barrow-in-Furness","16254":"Basildon","12402":"Basingstoke","5826":"Bath","13289":"Beddgelert","15082":"Bedford","4868":"Belfast","4869":"Belper","13874":"Benfleet","5827":"Benson","15514":"Berkhamsted","4870":"Berwick Upon Tweed","12948":"Betws-y-Coed","18776":"Bexley","14530":"Bicester","4871":"Billericay","18436":"Birkenhead","4872":"Birmingham","14592":"Blackburn","14686":"Blackpool","12526":"Bolton","12480":"Bournemouth","13062":"Bracknell","18772":"Bradford","4873":"Braemar","4874":"Brecon","4875":"Brentwood","18820":"Brighton","14260":"Bristol","4876":"Broomfield","42004":"Burgess Hill","14654":"Burnley","4877":"Burton Upon Tren","13812":"Bury","15835":"Bury St Edmunds","16500":"Camberley","4878":"Cambridge","4879":"Canterbury","5957":"Cardiff","14443":"Carlisle","14065":"Carrickfergus","42384":"Chalgrove","5832":"Chatham","13641":"Chelmsford","4880":"Cheltenham","4881":"Chester","42879":"Chesterfield","12160":"Chichester","41768":"Chorley","14056":"Church Stretton","5949":"Cladich","4884":"Colchester","16204":"Congleton","17534":"Coniston","42888":"Corsham","4885":"Coventry","13575":"Crawley","15410":"Crewe","13913":"Croydon","4886":"Cumbernauld","13711":"Dartford","4887":"Dartmouth","5833":"Derby","17468":"Derry","4889":"Doncaster","13696":"Dorchester","15377":"Dorking","5834":"Dover","16659":"Dudley","41867":"Dumbarton","18091":"Dumfries","4890":"Dunbar","14217":"Dunblane","4891":"Dundee","14067":"Dunfermline","4892":"Durham","16058":"East Molesey","17521":"East Preston","12501":"Eastbourne","12374":"Eastrea","4893":"Edinburgh","18992":"Elgin","41763":"Ellesmere","12883":"Ely","16825":"Enfield","14510":"Epsom","5835":"Exeter","4894":"Falkirk","5836":"Falmouth","42388":"Faringdon","42034":"Farmington","14604":"Farnham","42347":"Feltham","12829":"Fleet","4895":"Forres","42315":"Frosterley","5950":"Glasgow","4896":"Glastonbury","12562":"Gloucester","15956":"Gosport","4898":"Grangemouth","12626":"Gravesend","16057":"Grays","4899":"Great Wilbraham","4900":"Greenock","12752":"Grimsby","11747":"Guildford","14506":"Guilford","11938":"Halifax","5010":"Hamilton","15553":"Harlow","41733":"Harpenden","14713":"Harrow","4902":"Hartlepool","18952":"Haslemere","13977":"Hastings","14917":"Hatfield","12529":"Haverfordwest","4903":"Haverhill","4904":"Hawarden","5951":"Hawick","11776":"Hemel Hempstead","15302":"Hereford","14999":"Hertford","41893":"Heston","16056":"Hexham","13019":"High Wycombe","13643":"Hoddesdon","5958":"Holyhead","12420":"Hornchurch","14160":"Horsham","12108":"Huddersfield","5837":"Hull End","13296":"Huntingdon","14801":"Hyde","17707":"Ilford","41721":"Inverkeithing","4905":"Inverness","5838":"Ipswich","4906":"Keighley","4907":"Kelso","18628":"Kendal","17805":"Kenilworth","4908":"Kennet","4909":"Kettering","18578":"Kidsgrove","18984":"Kilmarnock","4910":"Kingston Upon Hull","5952":"Kirkwall","18257":"Lakenheath","15425":"Lampeter","13182":"Lancaster","4911":"Laughton","13488":"Leamington","18824":"Leeds","13135":"Leek","17849":"Leicester","17716":"Leigh","12836":"Lerwick","13387":"Letchworth","4912":"Lewes","41767":"Leyland","13546":"Lichfield","5840":"Lincoln","19039":"Little Chalfont","16778":"Liverpool","13442":"Llandrindod Well","5953":"Loch Ness","12008":"London","15035":"Loughborough","15518":"Loughgall","15011":"Louth","18492":"Lowestoft","14023":"Luton","4913":"Machynlleth","12416":"Maidenhead","12230":"Maidstone","14722":"Manchester","4914":"Mansfield","4915":"Margate","4916":"Marlborough","17889":"Marlow","18870":"Melborne","16170":"Melton Mowbray","4917":"Merton","5844":"Middlesbrough","5959":"Milford","15181":"Millom","12315":"Milton Keynes","12089":"Mold","18816":"Montrose","5954":"Motherwell","18574":"Nantwich","4918":"Newark","17097":"Newbury","5845":"Newcastle","4919":"Newcastle Upon Tyne","19040":"Newport","41682":"Newquay","13629":"Northallerton","4922":"Northampton","18577":"Northwich","42209":"northwold","15080":"Norwich","5847":"Nottingham","4923":"Oban","11975":"Oldham","6474":"Omagh","17161":"Oxford","15422":"Oxshott","18627":"Penrith","4925":"Penzance","16404":"Perth","5848":"Peterborough","4926":"Plains","4927":"Plymouth","15551":"Pontypridd","14208":"Poole","4928":"Portsmouth","17642":"Portstewart","41766":"Preston","5011":"Prestwick","18579":"Radway Green","42069":"Ramsgate","11775":"Reading","14706":"Redditch","16276":"Ringwood","15522":"Ripon","14673":"Rochester","15968":"Romford","41857":"Rugby","15289":"Runcorn","17520":"Rustington","14052":"Saint Albans","16462":"Salford","4931":"Salisbury","42295":"Sandwich","17690":"Sandy","4932":"Scarborough","13975":"Seaford","12003":"Shaftesbury","18891":"Sheffield","5850":"Shrewsbury","13178":"Slough","14708":"Solihull","4935":"Southampton","4936":"Southborough","14524":"Southend-on-Sea","13970":"Southport","42260":"St Albans","5955":"St Andrews","15841":"St Asaph","18576":"St Helens","16114":"St Ives","12717":"Stafford","41746":"Staines","14051":"Stanmore","16656":"Stansted","42032":"Stevenage","5012":"Stirling","11801":"Stockport","14198":"Stockton-on-Tees","4937":"Stoke On Trent","42386":"Stranraer","4938":"Stratford-Upon-Avon","4939":"Stroud","18615":"Sudbury","11860":"Sunderland","16393":"Sutton","5960":"Swansea","12853":"Swindon","4941":"Taunton","5851":"Teeside","13973":"Telford","4943":"Truro","17702":"Virginia Water","5852":"Waddington","12059":"Wakefield","4945":"Wallingford","4947":"Wareham","5853":"Warrington","4948":"Warwick","4949":"Watford","12009":"Wellingborough","12528":"Wellington","13366":"Wells","12530":"Welwyn Garden City","16785":"Weston Under Lizard","16334":"Wetherby","18171":"Weymouth","4950":"Whitby","13308":"Whitehaven","42387":"Whitehead","5956":"Wick","17581":"Wilmslow","5854":"Wimbledon","12524":"Wimborne Minster","12551":"Winchester","15946":"Windsor","18573":"Winsford","4952":"Wisbech","4953":"Wisborough Green","12982":"Woking","18769":"Wokingham","13287":"Wolverhampton","17904":"Woodford","18086":"Woolavington","11783":"Worcester","12128":"Worthing","5961":"Wrexham","13630":"Yarm","17015":"Yeovil","11824":"York"}
Here is my Javascipt:
$('#current-country').change(function(){ //any select change on the dropdown with id country trigger this code
$('.select-current-city').show();
$("#current-cities > option").remove(); //first of all clear select items
var country_id = $('#current-country').val(); // here we are taking country id of the selected one.
$.ajax({
type: "POST",
url: "<?php echo base_url()?>map/get_cities/"+country_id, //here we are calling our user controller and get_cities method with the country_id
success: function(cities) //we're calling the response json array 'cities'
{
$.each(cities,function(id,city) //here we're doing a foeach loop round each city with id as the key and city as the value
{
var opt = $('<option />'); // here we're creating a new select option with for each city
opt.val(id);
opt.text(city);
$('#current-cities').append(opt); //here we will append these new select options to a dropdown with the id 'cities'
});
}
});
});
Has anyone any suggestions on how I can process this much data in the browser?
I'm using PHP (Codeigniter), MySQL and jQuery.
I would recommend creating an array of your new option nodes, and then appending them en masse. Doing them one at a time may be what's killing you.
var newOptions = [];
$.each(cities,function(id,city) {
var opt = $('<option />', { "val": id, "text": city });
newOptions.push(opt[0]); //need to push actual dom node - thanks RightSaidFred
});
$('#current-cities').append(newOptions);
Or should this be clearing previous options in the dropdown? If so:
$('#current-cities').html(newOptions);
First double check you are not making the same AJAX request more than once.
A quick and easy solution would be to split your AJAX requests in more than one. Start by dividing it into two, and if that still isn't enough, divide them by 3 or more.
You can then check which JSON size is the right one for you, and use that one. Or you can have your php determine how much requests are needed based on the number of total cities.
For really large lists, I had to split the requests into 100 items each. The first request I would get the first piece of list along with a bit of data indicating how much requests I had to make to obtain the full list, append the new nodes, then I would make the remaining requests, until I got the full list.
I don't see how that would crash for you. Here I am doing the worst possible thing and it is blazing fast:
http://jsfiddle.net/HZnYQ/
Each time you select something, I remove all elements one by one and then append them one by one, and it's still instant. Actually my CPU doesn't even make a note of it.

webOS/Ares : read JSON from URL, assign to label

I've used the webOS Ares tool to create a relatively simple App. It displays an image and underneath the image are two labels. One is static, and the other label should be updated with new information by tapping the image.
When I tap the image, I wish to obtain a JSON object via a URL (http://jonathanstark.com/card/api/latest). The typcial JSON that is returned looks like this:
{"balance":{"amount":"0","amount_formatted":"$0.00","balance_id":"28087","created_at":"2011-08-09T12:17:02-0700","message":"My balance is $0.00 as of Aug 9th at 3:17pm EDT (America\/New_York)"}}
I want to parse the JSON's "amount_formatted" field and assign the result to the dynamic label (called cardBalance in main-chrome.js). I know that the JSON should return a single object, per the API.
If that goes well, I will create an additional label and convert/assign the "created_at" field to an additional label, but I want to walk before I run.
I'm having some trouble using AJAX to get the JSON, parse the JSON, and assign a string to one of the labels.
After I get this working, I plan to see if I can load this result on the application's load instead of first requiring the user to tap.
So far, this is my code in the main-assistant.js file. jCard is the image.
Code:
function MainAssistant(argFromPusher) {}
MainAssistant.prototype = {
setup: function() {
Ares.setupSceneAssistant(this);
},
cleanup: function() {
Ares.cleanupSceneAssistant(this);
},
giveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
},
jcardImageTap: function(inSender, event) {
//get "amount_formatted" in JSON from http://jonathanstark.com/card/api/latest
//and assign it to the "updatedBalance" label.
// I need to use Ajax.Request here.
Mojo.Log.info("Requesting latest card balance from Jonathan's Card");
var balanceRequest = new Ajax.Request("http://jonathanstark.com/card/api/latest", {
method: 'get',
evalJSON: 'false',
onSuccess: this.balanceRequestSuccess.bind(this),
onFailure: this.balanceRequestFailure.bind(this)
});
//After I can get the balance working, also get "created_at", parse it, and reformat it in the local time prefs.
},
//Test
balanceRequestSuccess: function(balanceResponse) {
//Chrome says that the page is returning X-JSON.
balanceJSON = balanceResponse.headerJSON;
var balanceAmtFromWeb = balanceJSON.getElementsByTagName("amount_formatted");
Mojo.Log.info(balanceAmtFromWeb[0]);
//The label I wish to update is named "updatedBalance" in main-chrome.js
updatedBalance.label = balanceAmtFromWeb[0];
},
balanceRequestFailure: function(balanceResponse) {
Mojo.Log.info("Failed to get the card balance: " + balanceResponse.getAllHeaders());
Mojo.Log.info(balanceResponse.responseText);
Mojo.Controller.errorDialog("Failed to load the latest card balance.");
},
//End test
btnGiveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
}
};
Here is a screenshot of the application running in the Chrome browser:
In the browser, I get some additional errors that weren't present in the Ares log viewer:
XMLHttpRequest cannot load http://jonathanstark.com/card/api/latest. Origin https://ares.palm.com is not allowed by Access-Control-Allow-Origin.
and
Refused to get unsafe header "X-JSON"
Any assistance is appreciated.
Ajax is the right tool for the job. Since webOS comes packaged with the Prototype library, try using it's Ajax.Request function to do the job. To see some examples of it, you can check out the source code to a webOS app I wrote, Plogger, that accesses Blogger on webOS using Ajax calls. In particular, the source for my post-list-assistant is probably the cleanest to look at to get the idea.
Ajax is pretty much the way you want to get data, even if it sometimes feels like overkill, since it's one of the few ways you can get asynchronous behavior in JavaScript. Otherwise you'd end up with code that hangs the interface while waiting on a response from a server (JavaScript is single threaded).

Django Dynamic Drop-down List from Database

I wanted to develop a Django app and one of the functionalities I'd like to have is dynamic drop-down lists...specifically for vehicle makes and models...selecting a specific make will update the models list with only the models that fall under that make....I know this is possible in javascript or jQuery (this would be my best choice if anyone has an answer) but I don't know how to go about it.
Also, I'd want the make, model, year and series to be common then the other attributes like color, transmission etc to be variables so that one needs only enter the make, model, year, and series only for a new vehicle. Any ideas would be highly appreciated.
The 3 things you mention being common, make, model, year, would be the 3 input values. When given to the server, an object containing the details would be returned to the calling page. That page would parse the object details (using JavaScript), and update the UI to display them to the user.
From the Django side, there needs to be the facilities to take the 3 inputs, and return the output. From the client-side, there needs to be the facilities to pass the 3 inputs to the server, and then appropriately parse the server's response.
There is a REST api framework for Django that makes it rather easy to add the "api" mentioned above -- Piston. Using Piston, you'd simply need to make a URL for that resource, and then add a handler to process it. (you'll still need to skim the Piston documentation, but this should give you an idea of what it looks like)
urls.py:
vehicle_details = Resource(handler=VehicleDetails)
url(r'^vehicle/(?<make>.*)/(?<model>.*)/(?<year\d{2,4}/(?P<emitter_format>[a-z]{1,4}), vehicle_details, name='vehicle_details'),
handler.py:
class VehicleDetails(BaseHandler):
methods_allowed = ('GET',)
model = Vehicles #whatever your Django vehicle model is
def read(self, request, *args, **kwargs):
# code to query the DB and select the options
# self.model.objects.filter()...
# Build a custom object or something to return
return custom_object
This simply sets up the url www.yoursite.com/vehicle/[make]/[model]/[year]/json to return a custom data object in JSON for jquery to parse.
On the client side, you could use jquery to setup an event (bind) so that when all 3 drop downs have a value selected, it will execute a $.get() to the api URL. When it gets this result back, it passes it into the Jquery JSON parser, and gives the custom object, as a javascript object. That object could then be used to populate more drop down menus.
(Big warning, I just wrote the following off the top of my head, so it's not meant to be copy and pasted. It's just for the general idea.)
<script type="text/javascript">
// On document load
$(function() {
$('#dropdown_make').bind('change', checkForValues());
$('#dropdown_model').bind('change', checkForValues());
$('#dropdown_year').bind('change', checkForValues());
});
function checkForValues() {
if ($('#dropdown_make').val() && $('#dropdown_model').val() && $('#dropdown_year').val())
updateOptions();
}
function updateOptions() {
url = '/vehicle/';
url += $('#dropdown_make').val() + '/';
url += $('#dropdown_model').val() + '/';
url += $('#dropdown_year').val() + '/';
url += 'json/';
$.get(url, function(){
// Custom data object will be returned here
})
}
</script>
This is uncanny: Dynamic Filtered Drop-Down Choice Fields With Django
His question:
"Here is the situation: I have a database with car makes and models. When a user selects a make, I want to update the models drop-down with only the models associated with that make. ... Therefore I want to use Ajax to populate the data."
You're not the same guy? :)

Categories

Resources