I have a table that populates prices from two apis. Unfortuantly this isn't sorted. Annoyingly. On each api however, it is sorted ^_^ So the issue i have is say site b is cheaper than site a. As it currenlty stands wouldn't work.
Heres my code. at the moment its just one api.
Forgot to mention, As it stands its site a ontop of site b in the same table. if there is a row thats cheaper tthen the row would have to move preferably.
Sam
$.ajax({
type: 'GET',
crossDomain: true,
dataType: 'json',
url: 'api link here',
success: function (json) {
//var json = $.parseJSON(data);
for(var i =0;i < json.results.length;i++) {
var title = json.results[i].section;
var price = json.results[i].price;
var href = json.results[i].quantity;
var button = "<button class='redirect-button' data-url='button link'>Link</button>";
$("#apple").append("<tbody><tr><td>"+title+"</td><td>"+href+"</td><td>"+price+"</td><td>"+button+"</td></tr></tbody>");
$("#apple").find(".redirect-button").click(function(){
location.href = $(this).attr("data-url");
});
So (assuming I understand this correctly), you want to have the rendered data be sorted by price? Luckily, that's easy to do :).
Here's a js fiddle so you can experiement: http://jsfiddle.net/e9sdb91v/
Here's the basic code you need:
success: function (data) {
var json = data.sort(sorter);
// Rest of your code goes here
}
You need to obviously write the sorter function as well:
function sorter(a, b) {
return (a.price - b.price);
}
That's basically it, sorter can be as simple or complex as you like (this will sort your objects from low to high on price). Just sort, then render.
If you need further clarification, just post a comment :).
Note: This sorts the data before rendering, so it assumes you are starting from scratch each time, if you are trying to add rows dynamically into the correct place in the #apple div, then that'll be slightly different (and you'll need to amend your question).
Related
I have django-tables2 set up and working well. I have set my table to be able to update checkbox columns directly from the displayed list. However when my displayed table paginates and I update a value it refreshes the entire page thus sending me back to the first page and I then have to click 'next' to get back to where I was. So I thought it might be a good idea to throw knockout.js into the mix to bind my individual columns to the corresponding data in my postgres database. According to the blurb this would allow me to simply refresh the item clicked on without having to refresh the entire page. I read the tutorial for knockout.js and all seems great and exactly what I am looking for. I've modified my views and written my js file etc and I am almost there. I have the JSONResponse from my views.py returning the correct number of rows, however, my django-tables2 tables are rendering each record as a header (ie th) in my table instead of the data as a row (ie td). Feeling like I've fallen at the last hurdle, I was wondering if anyone can shed any light on how I can fix this last bit of the puzzle please.
view.py
def mydatalist(request):
data = []
user = get_current_user()
query = Q(user_fkey=user.id)
query.add(Q(deleted__isnull=True), Q.AND)
query.add(Q(master=True), Q.AND)
tasks = Task.objects.filter(query)
for task in tasks:
data.append({"code":task.code, "name":task.name, etc})
return JsonResponse(data, safe=False)
my .js file
function Task(data) {
this.code = ko.observable(data.code);
this.name = ko.observable(data.name);
etc
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
$.getJSON('http://myweb.org/tasks/mydatalist/', function (data) {
if(data){
var mappedTasks = $.map(data, function (item) {
return new Task(item);
});
} else {
alert('data empty!');
}
self.tasks(mappedTasks);
});
}
ko.applyBindings(new TaskListViewModel());
my django-tables2 tables.py file
class MasterTable(ColumnShiftTable):
code = tables.Column(attrs={'th':{'class':'centered nodec'}})
name = tables.LinkColumn(attrs={'th':{'class':'centered nodec'}})
etc
class Meta:
model = Task
fields = ('code','name', etc)
template_name = 'django_tables2_column_shifter/bootstrap3.html'
attrs={'id':'masterlist', 'class': 'table table-noborder', 'data-bind': 'foreach: tasks, visible: task().length > 0'}
row_attrs={'id': lambda record: record.pk}
So basically everything is kind of working except that when rendered, my django-tables2 table is rendering 11 headers and no data rows instead of 1 header and 10 data rows.
If anyone can shed any light I really would appreciate it or alternatively if someone can suggest another way to achieve not having to refresh the entire page each time, that would be great also.
Hi I am just beginning with angular and I am struggling to find the answer to what I'm sure is quite a simple thing to do.
I am currently getting the values of some input boxes and pushing them into my scope. This is creating one long 'array' eg:
['data-1','data-2','data-3']
I would like to format my data in the following way instead
$scope.data = [
{
'header1': 'data1-1',
'header1': 'data1-2',
'header1': 'data1-3'
},
{
'header1': 'data2-1',
'header1': 'data2-2',
'header1': 'data2-3'
}
]
This is my function as it currently is.
$scope.createRow = function(){
angular.forEach(angular.element("input"), function(value, key){
$scope.td.push($(value).val());
});
}
Any help or pointers would be greatly appreciated as I am just getting my head round the angular way
Doing this isn't hard... but before I give you a gun to shoot yourself in the foot, just to say that I think it would be beneficial to explain WHY you want structure in that other format you are mentioning. You seem to have lots of data repetition and that's always a red flag.
Now for the code, you just need to create object before pushing it to the array like:
$scope.createRow = function(){
angular.forEach(angular.element("input"), function(value, key){
var obj = {
"header1": val + "-1",
"header2": val + "-2"
};
$scope.td.push(obj);
});
}
EDIT:
OK, so you are trying to add new row to the table. First of all, you shouldn't be doing angular.forEach, but rather those input elements in HTML should bind to existing scope object, like:
// obviously use better names than Input1Value
// I am here just giving you example
$scope.bindData = {
Input1Value: null,
Input2Value: null
};
// in HTML you will do
// <input ng-model="bindData.Input1Value" />
// <input ng-model="bindData.Input2Value" />
Now that you've eliminated that nasty angular.forEach you need to have some kind of event handler, for example when user clicks the button you want to add this object to the array to which table is data bound. Just be sure to clone the $scope.bindData object when you add it to array.
$scope.createRow = function(){
var newRowData = $scope.cloneObject($scope.bindData);
$scope.td.push(newRowData);
}
// http://heyjavascript.com/4-creative-ways-to-clone-objects/
// https://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object
$scope.cloneObject = function(objToClone) {
var newObj = (JSON.parse(JSON.stringify(objToClone)));
}
To close this answer off - keep in mind, if you ever find yourself directly referencing HTML DOM elements in Javascript with AngularJS - you are doing something wrong. It's a nasty habit to eliminate, especially if you are coming from jQuery background (and how doesn't?), where everything is $("#OhHiThere_ElementWithThisId).
Obviously the main thread on this topic on StackOverflow is this one:
“Thinking in AngularJS” if I have a jQuery background?
However I find that it's too theoretical, so Google around and you may find better overviews like:
jQuery vs. AngularJS: A Comparison and Migration Walkthrough
Is this possible.. here's what I have atm, but my data object is just returning a load of jargon, what am I doing wrong? Am I doing anything.. right, for that matter?
I basically want to print out a list of a users videos (thumbnail and title, and make each one a clickable link to the video itself)
Thanks!
$(document).ready(function(){
$player.init();
})
var $player = (function(){
var player = {};
player.init = function(){
//init Youtube knockout
player.initYoutubeKnockout();
}
player.knockoutModel = {
videoData : ko.observableArray([]),
}
player.initYoutubeKnockout = function()
{
//load the Youtube json feed
$.ajax({
url: 'http://gdata.youtube.com/feeds/api/users/USERNAME/uploads?v=2&alt=json',
type: 'GET',
dataType: 'jsonp',
data: {
count: 5
},
success: function(data, textStatus, xhr) {
player.doYoutubeKnockout(data.item);
}
});
}
player.doYoutubeKnockout = function( data )
{
player.knockoutModel.videoData(data);
ko.applyBindings(player.knockoutModel, $('#youtube-feed')[0]);
console.log($(this));
}
return player;
})();
Frankly you weren't doing much at all.
The JSON data you get back from YouTube is not from data.item, it's in a completely different structure.
I'm assuming you wish to get 5 uploads from the user. The parameter name would be max-results, not count.
Probably the only thing you did fine was set up the url but that's about it.
You need to examine how the JSON returned looks like. Check the API reference for the structure of an atom feed. This is in XML but the corresponding JSON responses will have pretty much the same format with some minor differences. Examine the object by writing it to the console to verify you're getting the right properties.
Once you understand that, you need to use the correct query to get what you're expecting. Check out their API reference on their query parameters.
To help simplify your knockout code, I would strongly recommend you take the response you get back and map it to an object with simplified property names. For instance, to get the thumbnails for an entry, you would have to access the media$group.media$thumbnail array. It would be easier if you can just access it through thumbnail.
Also, if your elements you are binding to need to bind multiple values, it would help to map the values in such a way that your bindings are made easier. For instance, when using the attr binding, you'd set up a property for each of the attributes you want to add. Instead you could just group all the properties in an object and bind to that.
I wrote up a fiddle applying all that I said above to do as you had asked for. This should help give you an idea of what you can do and how to do it.
Demo
I wrote code below that is working perfectly for displaying the results of my sales tax calculation into a span tag. But, I am not understanding how to change the "total" value into a variable that I can work with.
<script type="text/javascript">
function doStateTax(){
var grandtotalX = $('#GRANDtotalprice').val();
var statetaxX = $('#ddl').val();
$.post('statetax.php',
{statetaxX:statetaxX, grandtotalX:grandtotalX},
function(data) {
data = $.parseJSON(data);
$('.products-placeholder').html(data.products);
$('.statetax-placeholder').html(data.statetax);
$('.total-placeholder').html(data.total);
// ...
});
return false;
};
</script>
Currently, $('.total-placeholder').html(data.total); is successfully placing the total number into here:
<span class="total-placeholder"></span>
but how would I make the (data.total) part become a variable? With help figuring this out, I can pass that variable into a hidden input field as a "value" and successfully give a proper total to Authorize.net
I tried this and id didn't work (see the testtotal part to see what I'm trying to accomplish)..
function(data) {
data = $.parseJSON(data);
$('.products-placeholder').html(data.products);
$('.statetax-placeholder').html(data.statetax);
$('.total-placeholder').html(data.total);
$testtotal = (data.total);
// ...
If you are using a hidden field inside a form, you could do:
//inside $.post -> success handler.
$('.total-placeholder').html(data.total);
$('input[name=yourHiddenFieldName]', yourForm).val(data.total);
This will now be submitted along with the usual submit. Or if you want to access the data elsewhere:
var dataValue = $('input[name=yourHiddenFieldName]', yourForm).val();
The "data" object you are calling can be used anywhere within the scope after you have a success call. Like this:
$.post('statetax.php',
{statetaxX:statetaxX, grandtotalX:grandtotalX},
function(data) {
data = $.parseJSON(data);
var total = data.total;
var tax = data.total * 0.19;
});
return false;
};
Whenever you get an object back always try to see with an alert() or console.log() what it is.
alert(data); // This would return <object> or <undefined> or <a_value> etc.
After that try to delve deeper (when not "undefined").
alert(data.total); // <a_value>?
If you want 'testotal' to be recognized outside the function scope, you need to define it outside the function, and then you can use it somewhere else:
var $testtotal;
function(data) {
data = $.parseJSON(data);
$('.products-placeholder').html(data.products);
$('.statetax-placeholder').html(data.statetax);
$('.total-placeholder').html(data.total);
$testtotal = (data.total);
EDIT:
The comments are becoming too long so i'll try and explain here:
variables defined in javascript cannot be accessed by PHP and vice versa, the only way PHP would know about your javascript variable is if you pass it that variable in an HTTP request (regular or ajax).
So if you want to pass the $testtotal variable to php you need to make an ajax request(or plain old HTTP request) and send the variable to the php script and then use $_GET/$_POST to retrieve it.
Hope that answers your question, if not then please edit your question so it'll be clearer.
I am setting up cycling quotes for a website, and I'm having trouble reloading the data when after it has already been used once.
I've set up a XML file with a bunch of data. The data includes a quote, an author, and the job title of the author (quote, author, title).
I then have a jQuery .ajax call and store it in the variable xmlData.
xmlData is then used to append or add html to specified id tags.
I am using setInterval() in order to move through the xml data.
The idea is to go through it in a loop like: 1 | 2 | 3| 1| 2 | 3 and so on. But when it comes back around, after the data has been appended to an ID, it doesn't show up anymore. It is as if the data was removed from the XML file.
Any help would be appreciated. Code is below, along with the website URL where I am working on the test.
<script language="javascript" type="text/javascript">
var xmlData;
var xmlFAILdata;
var nextE = 0;
var ttlE;
var quote;
var author;
var title;
$(function(){
$.ajax({
type: "GET",
url:"/wp-content/themes/privilegeofpersecution/endorsements.xml",
data: "",
dataType:"xml",
async: false,
success: function(xml){
//alert("XML SUCCESS!");
xmlData = xml;} ,
error: function(xmlFAIL){
alert("XML FAIL");
}
});
ttlE = $(xmlData).find('endorsement').length;
//Since .length return the number starting at 1 rather than 0 subtract 1 for accuracy
ttlE -= 1;
//On pageload, load in the first Endorsement into variables
quote = $(xmlData).find('endorsement').eq(0).children('quote');
author =$(xmlData).find('endorsement').eq(0).children('author');
title =$(xmlData).find('endorsement').eq(0).children('title');
//Append variables to id containers
$("#quote").html(quote);
$("#author").html(author);
$("#title").html(title);
//executes the function "next" which places the next endorsement
setInterval("next()", 5000);
});
function next(){
console.log('Next Function Started');
if(nextE >= ttlE){
nextE = 0;
}
else{
nextE++;
}
console.log('nextE = ' + nextE);
quote = $(xmlData).find('endorsement').eq(nextE).children('quote');
author =$(xmlData).find('endorsement').eq(nextE).children('author');
title =$(xmlData).find('endorsement').eq(nextE).children('title');
$("#quote").html(quote);
$("#author").html(author);
$("#title").html(title);
}
</script>
Here is the website: http://privilegeofpersecution.com/wp-content/themes/privilegeofpersecution/xmltest.html
I was able to fix the problem by adding .clone() to the variable assignment. This way I'm not just placing the XML object in the DOM and overwriting it. rather, I am copying the data from the XML each time I need it so that it stays in tact.
quote = $(xmlData).find('endorsement').eq(0).children('quote').clone();
author =$(xmlData).find('endorsement').eq(0).children('author').clone();
title =$(xmlData).find('endorsement').eq(0).children('title').clone();