I'm modifying a draft website which is basically mde by storing data in local storage and fetching and rendering it. On the cart.html page input are created dynamically, depending upon how many packages are added in the cart.
There are 2 prices, one which is package's price (works totally fine) and the other one is Total price of all the items in cart, which doesn't seem to update and adds on values to the previous value. I'm not sure what I'm doing wrong but any help would be great!
I'm also attaching stackblitz to get better understanding of my application. Please readme if you want instructions
cart.html
<div class="totalPrice">
<table>
<tr>
<td>Total Price</td>
<td id="totalPriceCount" data-total=""></td>
</tr>
</table>
</div>
JS: (Don't really have idea how to achieve)
$(".myInput").on('input', function () {
varCurrentVal = this.value;
if (varCurrentVal == 0) {
return;
}
var closestSibAttr = $(this).parent().parent().find("#quantityBasedPrice").attr("data-val");
$(this).parent().parent().find("#quantityBasedPrice").html(varCurrentVal * closestSibAttr).attr("data-total", varCurrentVal * closestSibAttr);
// code to update #totalPriceCount to sum all the values into the Total Price
})
Stackblitz: https://stackblitz.com/edit/web-platform-8cynxp?file=turkey.html
Related
Using angularjs (1.3) with webapi here.
I have UI where the user can upload a excel file. My api reads the excel file and returns rows data back to the UI in JSON.
The UI then reads the JSON and binds it back the UI table.
The rows and columns of this UI table are dynamically generated and are not fixed, because of which I am using contenteditable in HTML as the user can add more rows.
I can read from the the JSON fine and populate the array that holds these json values. The issue is while rendering, the screen is frozen and takes time to render all the data.
I am currently binding about 800 rows and the screen freezes and takes about 10-15 seconds or more to fill up the UI table. I would be having lot more data so looking for a solution for this.
I tried to debug and can see that there is no issue getting data back from the API, and reading JSON from the API. There is also no issue while populating the array.
Once the array populates thats when the issue comes. The UI freezes and takes time to render this data.
I am not sure whats going on here or why it takes so time to render. Below is some sample relevant code:
//Read json from the API
$http.get('https://api.myjson.com/bins/d1ugw').success(function(data) {
if (data.length > 0) {
$scope.setJson = data;
$scope.initializeTable(true);
var columns = $scope.targetTable.columns;
//These are the 3 columns of the Table but can vary dynamically(currently just hardcoding it)
var refColName = "state, month , year";
//Push the columns to the table array
var colArray = refColName.split(',');
for (var i = 0; i < colArray.length; i++) {
$scope.targetTable.columns.push({
id: columns.length,
refColName: refColName.split(',')[i]
});
}
//Read the values from the json
var idValues = $scope.getTableValues($scope.setJson, 'id');
var commentValues = $scope.getTableValues($scope.setJson, 'comment');
var rowValues = $scope.getTableValues($scope.setJson, 'refcol');
var setIdValues = $scope.getTableValues($scope.setJson, 'sid');
//Push the data back to the table array.
$scope.pushRowData($scope.targetTable, rowValues, commentValues, idValues, setIdValues);
//Till the above steps everything happens quickly and I can see $scope.targetTable being populated with my json.
//But after the above step the screen just freezes and takes time to show the entire data on the UI table.
}
});
Below is the relevant code for the UI:
<tbody>
<tr ng-repeat="r in targetTable.rows">
<td class="fixed-width">
<span>
<a class="btn-xs" ng-show="row == $index" ng-if="targetTable.rows.length > 1"><i class="fa fa-times-circle" aria-hidden="true"></i></a>
</span>
<span contenteditable="true" ng-model="r.tableId" ng-change="addNewRow(r.tableId, r)">{{r.tableId}}</span>
</td>
<td class="fixed-width" contenteditable="true" ng-repeat="column in targetTable.columns" ng-model="r[column.id]" ng-change="rowDataChange(r[column.id])"></td>
<td class="comment-fixed-width" contenteditable="true" ng-model="r.comment" ng-change="rowDataChange(r.comment)"></td>
<td class="blank fixed-width" colspan="2" ng-model="r[column.id]"></td>
</tr>
</tbody>
I have created the below JSFiddle to show my example and issue I am facing.
http://jsfiddle.net/aman1981/u1vbeos5/312/
I have also added comments in my jsfiddle for showing what method does what.
Would appreciate if anyone can help my resovling this issue.
Here are some performance stats:
with contenteditable (~4000 digest calls) = 1.800ms -> http://prntscr.com/lweugn
without contenteditable (~4 digest calls) = 1.300ms -> http://prntscr.com/lweusn
with pagination just showing the first 50 results = 0.200ms -> http://prntscr.com/lwev09
You loose the most performance because of the DOM changes obviously. But keep in mind that the number and duration of digest cycles is key for good performance. Especially when you have a huge amount of watchers. Here is a Direct comparison:
http://prntscr.com/lwf1nn As you can see the digest loop is burning 30% of your performance overall but is not the reason for your frame drop. The frame drop is mostly caused of the DOM changes. Drawing such a big table takes some time.
Further the table starts rendering when your REST call is finished. This call takes in my case roughly additional 1.700ms. So it takes nearly 3.500ms from start until rendered results. Even with pagination 1.900ms.
I would recommend a pagination with search but you can try to increase the performance anyway.
Helpful links would be:
https://stackoverflow.com/a/47347260/8196542
https://www.codeproject.com/Articles/1173869/%2FArticles%2F1173869%2Fng-repeat-performance-degradation-at-case-of-very
First, I recommend that you upgrade the Angular version to the most advanced of course if possible.
Also check the animate version.
Beyond that you thought of using an advanced tabular component such as ag-grid ?,
I can load 10000 rows without any problem with it.
https://www.ag-grid.com/
Your code is triggering the $digest loop over and over.
The "watch" method counts how often the $digest cycle is actually called:
var nbDigest = 0;
$scope.$watch(function() {
nbDigest++;
console.log(nbDigest);
});
I bet this is the cause of your performance issues.
I have the following situation I can not solve. I would be very thankful if anyone had an idea:
My webpage contains a table of players. Each line (player) contains two checkboxes: One that selects if the player is active (checked) or not, the other which team he/she belongs to (checked=Team 1; unchecked=Team 2).
So each line looks sth like this:
<tr>
<td><input id="plyr2_active" type="checkbox" name="plyr_active[]" value="2"></td>
<td><input type="checkbox" id="plyr2_team" name="plyr_team[2]" data-on-color="danger" data-off-color="success" data-on-text="RED" data-off-text="GREEN" checked value="1"></td>
</tr>
I'd like to add a button that, when clicked, will run a function that randomizes the teams of the ACTIVE players. Meaning that the players will be shuffled and half of them belong to one, the other half to the other team.
What I tried: Get all checkbox states in an array, then shuffle() the array and try to change the checked-state via bootstrap. Miserably failed :-(
Any help will be much appreciated. Thanks!!
Okay, this should help to get you started. It shows how to pull a list of active players (using jQuery) from your table.
Assuming you have a button with an id of 'shuffleBtn':
<button id="shuffleBtn">Shuffle<button>
and a table with id 'players':
<table id='players'>
:
</table>
-
$("#shuffleBtn").click(function() {
var newPlayerArray = [],
id = 1;
$("#players tr td:first-child").each(function() {
if ($(this).find('input:first').prop('checked')) {
newPlayerArray.push(id);
}
id++;
});
console.log(newPlayerArray);
});
This will display an array of the active players (assuming the first row is player 1, the second player 2, etc.) on the console.
Example: [1,3,4]
It then iterates each row () and grabs the first column (). Then for each of those it finds the first <input> and checks if the 'checked' property is present (this means the checkbox has been clicked).
I am just pushing the row index (starting at 1) so you may need to change how you interpret the associated player.
It's my first time working with KnockoutJS, and I have a little bit of problem.
I'm trying to get multiple values from inputs then set the addition of the values to a observable or make a computed that get the result of the addition. But I can't figure out how, because the table it's generated from a database and I don't know the quantity of rows until I run the app. Any help will be appreciated. Thanks.
Here is a capture of the site
I need in the field "INVERSION TOTAL DEL MES" the adition of the values from the inputs from "IMPORTE TOTAL"
Here's the part of the html with the bindings
<tbody data-bind="foreach: RendicionesPager.pagedRows">
<tr><td class="text-right">$ <input style="width:90%;text-align:right" data-bind="textInput:ImporteTotal" /></td>
</tr>
</tbody>
<tr>
<td colspan="7" class="text-right" >INVERSION TOTAL DEL MES</td>
<td class="text-right"><span data-bind="text:'$ ' + InversionDelMes()"></span></td>
</tr>
Do something like:
InversionDelMes = ko.computed(function(){
return RendicionesPager.pagedRows.reduce(function(p,n){ return p.ImporteTotal + n.ImporteTotal ;});
});
You will need to adjust all contexts, add () if ImporteTotal is an observable etc.etc but you get the idea :)
Edit: to explain better, create a ko computed, that will be updated when RendicionesPager.pagedRows is changed, and each time it will aggregate the ImporteTotal field of all contained elements and return it.
Also have in mind that this will work when you add/remove items from your observable array RendicionesPager.pagedRows (if it is obsArray that is). If you want to recalculate your values as a total each time a user changes an input value then you would have to subscribe to each observable field and run a similar logic,for example
ImporteTotal.subscribe(function(){
myTotal = RendicionesPager.pagedRows.reduce(function(p,n){
return p.ImporteTotal + n.ImporteTotal ;
});
});
so that when any of the observables changes its value, it will fun this function which will in turn update the total value
I have a table displaying data from the database. I have a select box where the person can select the currency in which he wants the data to be displayed.
When he does so, i need the data to be refreshed and displayed as the new currency. And I can't figure out how to do so without refreshing the whole page.
Any ideas please?
<select id="currency">
<option value = "rub">В рублях</option>
<option value = "usd">USD</option>
<option value = "eur">EURO</option>
</select>
<table id="servers" cellpadding="0" cellspacing="0">
<tr>
<td width="400"><b>Сервер</b></td>
<td width="100"><b>1 кк адены</b></td>
<td width="100"><b>1 ккк адены</b></td>
</tr>
<?php
$sql = mysql_query("SELECT * FROM `prices`");
while($r = mysql_fetch_array($sql)) {
echo("\t\t<tr>\n");
echo("\t\t\t<td>".$r['name']."</td>\n");
echo("\t\t\t<td>$".round($r['kk']/$dollar, 2)."</td>\n");
echo("\t\t\t<td>$".round($r['kkk']/$dollar, 2)."</td>\n");
echo("\t\t</tr>\n");
} ?>
</table>
You can use Ajax, which allows to request the DB and retrieve the data without refreshing the whole page.
Here is an introduction : http://www.w3schools.com/jquery/jquery_ajax_intro.asp
Then, have a look to the jquery API and take a look at the examples : http://api.jquery.com/jQuery.ajax/
Good luck
If you can hold factors for data transformation (for conversion USD>AUS USD>EUR or whatever) you can delegate the change throughout the table by using one general selector.
first you place all the factors in the js vars like this(this must be doe inside php file and other stuff can be done in separated js):
var USDtoEUR = <?php echo $php2eur; ?>
Next thing you do, you bind event to click on the select box, button or whatever, let's say it is select with id "currency":
$('#currency'). click(function() {
switch ($('this').val()) {
case 'EUR' {
//Code we will discuss is going here
}
break;
//... etc...
So, we want to change all the data we are assuming is in USD on click, so we have all the factors to convert from usd to other values stored in separate vars USDtoXXX. Note that we need one USDtoUSD, too.
Now... Whatever the structure is, the element containing dynamically changed data should have class and inusd attributes like this:
<li class="price" inusd="123">123</li>
th price in usd should be stored to an attribute to keep it independant from the dom content that will change.
so for the above example we do this:
$('.price').each(function() {
$(this).text()=$(this).attr('inusd')*USDtoEUR; //If user selected EUR
}
Be carefull to use breaks and default in the switch statement... javascript switch lets cases drop their conditions through.
Also, when working with money, please do the in depth testing of the calculating functions, javascript can mess that upp, too, from time to time :D
I can't figure this out. I checked other questions regarding setting data attributes, seems to be a tricky enough thing.
The stripe button amount is purely for aesthetics, I'm trying to set it ('data-amount') each time a user updates the quantity select box.
Every time I change the quantity select an alert gives the correct amount and if I inspect the dom the 'data-amount' attribute appears to be set correctly but when I click the stripe button the modal shows the default data-amount, i.e nothing.
Anyone know how to do this?
view (form, select input not shown)
<div class="stripe-controls" align="center">
<script src="https://button.stripe.com/v1/button.js" class="stripe-button"
data-key="ENV['STRIPE_PUBLIC_KEY'] %>" data-amount="">
</script>
</div>
coffeescript
$ ->
$('#order_quantity').click(orderTotal)
orderTotal()
orderTotal = ->
quantity = $('#order_quantity').val()
price = $('#ticket-price').data('url')
total = quantity * price
$('.stripe-button').attr('data-amount', total)
alert total
Specify a custom amount using StripeCheckout.open().
Note: I work at Stripe.