Vue.js index and length resetting on each page - javascript

I'm having a strange problem that I can't solve. I wanted to add index number in for-each loop and count of total data in my vue.js component. I managed to do that, but my counter resets on every page within pagination, and items.lenght only counts data from current pagination page. I did the following:
<tr v-for="(item, index) in items" v-bind:key="item.id">
<td>{{index + 1}}</td>
<td>{{item.name}}</td>
</tr>
And to count all the data:
<div class="form-group">
Total data: {{items.length}}
</div>
Everything is working fine of first page of pagination, but when I select second page, it only counts total data from that specific page, and the counter is starting from 1 again. To illustrate, on first page it shows me that I have total of 15 data (and I have around 300), and indexing is fine:
And If I go to second page, it still shows me the same total, and index is starting from 1 again, where I want it to continue (ex 16, 17..)
Part of the Vue.js component:
mounted() {
this.getStatuses();
this.getSchoolYears();
if (this.items.length == 0) {
this.loadPage(this.pagination.current_page);
this.getObjects();
}
},
methods: {
getSaveStateConfig() {
return {
'cacheKey': 'ApplicationComponent',
};
},
addFilter(key, value) {
this.filters = this.filters.filter(function (obj) {
return obj.key !== key;
});
this.pagination.current_page = 1;
this.filters.push({key: key, value: value});
},
loadPageDebounce: _.debounce(function (page, parameters) {
this.loadPage(page);
}, 500),
loadPage(page, parameters) {
var parameters = '';
this.filters.forEach(function (obj, index) {
parameters = parameters + '&' + obj.key + '=' + obj.value;
});
var $this = this;
axios({
method: 'GET',
url: '/api/applications?page=' + page + parameters,
headers: {'X-CSRF-TOKEN': window.csrfToken, 'X-Requested-With': 'XMLHttpRequest'},
})
.then(function (response) {
// console.log('resposne', response);
$this.items = response.data.data
$this.pagination.total = response.data.total;
$this.pagination.last_page = response.data.last_page;
$this.pagination.current_page = response.data.current_page;
$this.pagination.from = response.data.from;
$this.pagination.to = response.data.to;
$this.pagination.next_page_url = response.data.next_page_url;
$this.pagination.prev_page_url = response.data.prev_page_url;
})
.catch(function (error) {
console.log(error);
});
},
loadData() {
this.loadPage(this.pagination.current_page, this.filters);
},
How to prevent this from happening when using vue.js pagination. All help appreciated.

Not the best solution I guess, but it should work as a quick fix.
<tr v-for="(item, index) in items" v-bind:key="item.id">
<td>{{(pagination.current_page*15)-15 + index+1}}</td>
<td>{{item.name}}</td>
</tr>
Edited better Solution as computed function to seperate view and logic:
<tr v-for="(item, index) in items" v-bind:key="item.id">
<td>{{getOverallIndex(index)}}</td>
<td>{{item.name}}</td>
</tr>
computed: {
getOverallIndex: function(index) {
return this.pagination.current_page*15)-15 + index + 1
}
}

In your method you have that:
.then(function (response) {
$this.items = response.data.data
$this.pagination.total = response.data.total; // THERE
If you have good backend code you should get your total count here.
So try to console.log($this.pagination.total) after that function or console.log(response.data.total) in that function. If you have there 15 not 300 it's error on your backend. Maybe is problem for binding this on axios.
Let me know if you founded that.
Good luck!

try like
<tr v-for="(item, index) in items" v-bind:key="item.id">
<td>{{items.indexOf(item)+1}}</td>
<td>{{item.name}}</td>
</tr>

Related

AngularJS ngtable not displaying data correctly

I have an ngTable that is loaded with data that proceeds from a "Get" call to a webapi. Then I reload the table, but the data it is not being displayed.
This is the *.js file
rdapp.controller('scoringTableCtrl', ['$location', '$scope', '$http', 'ngTableParams', '$filter',
function($location, $scope, $http, ngTableParams, $filter) {
$scope.teamList = [];
$http({
method: 'GET',
url: 'http://localhost:34592/api/scoringTable',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then(function(success) {
$scope.teamList = success.data;
addFieldsForSorting();
$scope.dataTable.reload();
}, function(error) {
console.log(error);
});
$scope.resolveHTML = function(position) {
if (position == 1 || position == 2 || position == 3) return 'champions';
if (position == 4) return 'champions-prev';
if (position == 5 || position == 6) return 'europa-league';
if (position == 18 || position == 19 || position == 20) return 'decline';
return '';
}
function addFieldsForSorting() {
// Add named properties for every stat value in recipients array, used for sorting the grid.
// Take value from vitalStats array, use alertIds to match between alpha keys and numeric keys.
$scope.teamList.forEach(function(team) {
for (var property in team) {
if (!team.hasOwnProperty(property)) {
continue;
}
if (property == 'name') {
continue;
}
if (property == 'position') {
continue;
}
var prop = 'sort_' + property;
team[prop] = -(team[property]);
}
team['sort_name'] = team.name;
team['sort_position'] = team.position;
});
}
$scope.dataTable = new ngTableParams({
page: 1, // show first page
count: 20, // count per page
sorting: {
sort_position: 'asc' // initial sorting
}
}, {
counts: [],
total: $scope.teamList.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
var requestData = $scope.teamList;
var orderedData = params.sorting() ? $filter('orderBy')(requestData, params.orderBy()) : requestData;
params.total(orderedData.length); // set total for recalc pagination
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
}
]);
This is my html:
<div class="position-view" style="position:relative; top:100px;">
<table ng-table="dataTable" class="table table-bordered table-border-important" ng-class="rec_spinner">
<tbody class="text-center">{{$data.length}}
<tr ng-repeat="team in $data">
<td class="{{resolveHTML(team.position)}}" data-title="''" sortable="'sort_position'">
{{team.position}}
</td>
<td data-title="'Clasificación'" sortable="'sort_name'">
{{team.name}}
</td>
<!--Total Stats-->
<td data-title="'PJ'" sortable="'sort_pj'">
{{team.pj}}
</td>
<td data-title="'PG'" sortable="'sort_pg'" >
{{team.pg}}
</td>
<td data-title="'PE'" sortable="'sort_pe'" >
{{team.pe}}
</td>
<td data-title="'PP'" sortable="'sort_pp'" >
{{team.pp}}
</td>
<td data-title="'GF'" sortable="'sort_gf'">
{{team.gf}}
</td>
<td data-title="'GC'" sortable="'sort_gc'">
{{team.gc}}
</td>
<td data-title="'PT'" sortable="'sort_pt'">
{{team.pt}}
</td>
</tr>
</tbody>
</table>
$data has no any data, but if I try {{dataTable}} I have all the data correctly loaded. Can anybody help me with this?, maybe there is something obvious that I am missing, but the point is that the table is creating the amount of rows and columns anyway but empty, it is very weird.
I think you are not storing $data anywhere. I cannot find $scope.data in your js file.
After long search I figured out the problem was pretty easy, was about the CamelCase notation. The problem is when you send info from a web api, if you don´t set custom notation for the parameters, they will be sent with the first letter capitalized.
So, we have two chooses here, establish custom notation or just use in our HTML the first letter capitalized. I hope this will help somebody in the future!

Get data from a key value structure and compare it with value from an ng-repeat in AngularJS

Two basic questions,
1) I have a controller where I define a list with a key, value structure and I want to access to the event name based on the eventID and log it in the console
$scope.events = [
{eventID:3200, eventName:"Event One"}
{eventID:3201, eventName:"Event Two"}
];
I tried this:
if($scope.events.eventID == 3200) {
console.log("Ok");
}
but it didnt worked :(
2) Then in my view I have a table where i print data coming from a WS, what I want is to print the description on the table depending on the eventID from my $scope.events list, I have a field on my ng-repeat named event that will let me compare with the eventID from the list but I dont know how to do this.
<tr ng repeat d in data>
<td>d.Description</td>
<td>d.anyValue</td>
</tr>
Any help is welcome, I really need it I'm new to Angular :)
Add method in controller
$scope.search=function(obj){
return obj.eventID === 3200;
}
add it to view
<tr ng-repeat="d in data | filter:search">
<td>d.Description</td>
<td>d.anyValue</td>
</tr>
for question number 1, try with this
if($scope.events[0].eventID == 3200) {
console.log("Ok");
}
for looping using this
angular.forEach($scope.events, function (value) {
if (value.eventId === 3200) {
{
console.log('OK');
}
});
for question number 2, create helper function to return eventName base on the ID.
$scope.getEventName = function (eventId) {
var result = '';
angular.forEach($scope.events, function (value) {
if (value.eventID === eventId) {
result = value.eventName;
return false;
}
});
return result;
}
<tr ng-repeat="d in (exportDataEventDesc.result.slice(5, exportDataEventDesc.result.length-2))">
<td>{{d.Description}}</td>
<td>{{d.anyValue}}</td>
<td ng-bind="getEventName(d.merchMetrics.EVENT_ID)" style="text-align: left"></td>
</tr>

Knockout JS binding on computed observable does not work

I am trying to add a new field to an asp.net MVC 5 website popup screen that uses Entity Framework 6 code first, Typescript and Knockout JS for databinding. I did not write this website. I have been making changes to it for a few months. The original programmer is no longer with the company. I have never worked with these technologies previously.
The new field is the result of a web service call. The web method does return results. However, the value is not displayed on the screen. I script runs and displays all the other data. The deferred call to the web service returns after the page displays. I will provide the markup and view model code. Any advice is greatly appreciated.
Below is the computed property that the HTML is bound to:
this.PredictedValue = ko.pureComputed(() => {
var age = "";
var race = "";
var height = "";
var studyId = this.Session().Study.PftCentralStudyId();
var predictedSetName;
var predictedSetId;
var gender;
if (this.StudyTestParameter().HasPredictedValues() == true) {
ko.utils.arrayForEach(this.Session().Study.StudyTestTypePredictedSets(),(item: Bll.TestTypePredictedSetVm) => {
if (String(item.TestType().Name()) == this.StudyTestParameter().TestType().Name())
predictedSetId = item.PredictedSetId();
});
if (predictedSetId == 0) {
return "";
}
else {
var match = ko.utils.arrayFirst(this.Session().PftCentralStudyPredictedSets(),(item: Bll.PftCentralPredictedSetsVm) => {
return String(item.Id) == String(predictedSetId)
});
predictedSetName = match.Name;
ko.utils.arrayForEach(this.Session().SessionValues(),(item: SessionValueVm) => {
if (String(item.StudySessionParameter().Name()) == "Age")
age = String(item.RecordedValue());
});
ko.utils.arrayForEach(this.Session().SessionValues(),(item: SessionValueVm) => {
if (String(item.StudySessionParameter().Name()) == "Race")
race = String(item.RecordedValue());
});
ko.utils.arrayForEach(this.Session().SessionValues(),(item: SessionValueVm) => {
if (String(item.StudySessionParameter().Name()) == "Height")
height = String(item.RecordedValue());
});
ko.utils.arrayForEach(this.Session().SessionValues(),(item: SessionValueVm) => {
if (String(item.StudySessionParameter().Name()) == "Sex")
gender = String(item.RecordedValue());
});
var promise = this.Session().CalculatePredicted(age, race, gender, height, String(this.StudyTestParameter().PftCentralStudyParameterId()), predictedSetName, studyId);
promise.done((data: string) => {
return data
});
}
}
else
return "";
});
CalculatePredicted = (age: string, race: string, gender: string, height: string, studySessionParameterId: string, predictedSetName: string, studyId: number) => {
var deferred = $.Deferred();
$.ajax({
url: "/Workflows/CalculatePredicted",
cache: false,
data: { age: age, ethnicity: race, gender: gender, height: height, studySessionParameterId: studySessionParameterId, testTypePredictedSetName: predictedSetName, studyId: studyId },
dataType: "json",
contentType: "application/json charset=utf-8"
}).done(data => {
deferred.resolve(data);
}).fail((jqXHR) => {
alert(jqXHR.responseText);
deferred.reject();
});
return deferred;
}
Below is the HTML.
<div>
Test Values:
<table class="width100pct gridtable">
<tbody data-bind="foreach: TestValues">
<tr>
<td data-bind="text: StudyTestParameter().Name"></td>
<td data-bind="text: RecordedValue"></td>
<td data-bind="text: ATSBestValue"></td>
<td data-bind="text: PredictedValue"></td>
</tr>
</tbody>
</table>
</div>
your promise object can't return for your computed. By the time the promise is done, the computed has long returned 'undefined'. That is the nature of async calls. Consider setting a different observable within the promise.done() function and bind to that new field in the UI instead; the computed function will still trigger if the underlying fields change.

Cannot use computable knockout js

I have a view model which is being initialized else where.
function PaymentPlanViewModel(root /* root not needed */, item) {
var self = this;
self.instalmentnbr = item.instalmentnbr;
self.Abbreviation = item.Abbreviation;
self.duedate = item.duedate;
self.capital_payment = ko.observable(item.capital_payment);
self.interest_payment = ko.observable(item.interest_payment);
self.overdue_payment = ko.observable(item.overdue_payment);
self.total_payment = ko.observable(item.total_payment);
self.capital_paid = ko.observable(item.capital_paid);
self.interest_paid = ko.observable(item.interest_paid);
self.overdue_paid = ko.observable(item.overdue_paid);
self.total_paid = ko.observable(item.total_paid);
self.INSERT_DT = item.INSERT_DT ;
};
self.total_remaining = ko.computed(function() {
var sum = 0;
sum += parseFloat(self.total_payment) - parseFloat(self.total_paid);
return sum.toFixed(2);
});
self.getPaymentPlan = function (request_orig_id) {
$.ajax({
type: 'POST',
url: BASEURL + 'index.php/moneyexchange/getPaymentPlanForRequest/' + auth,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: ko.toJSON({
request_orig_id : request_orig_id
})
})
.done(function(data) {
self.paymentPlan.removeAll();
$.each(data, function (index, item) {
// self.paymentPlan.push(item);
self.paymentPlan.push(new PaymentPlanViewModel(self, item));
});
self.nextDueDate(self.paymentPlan()[0].duedate);
})
.fail(function(xhr, status, error) {
alert(status);
})
.always(function(data){
});
};
This view model above is being initialized in this place,
// Initialize the MoneyBorrowedViewModel view-model.
$.getJSON(self.borrowmoneyUri, function (borrowedmoney) {
$.each(borrowedmoney, function (index, money) {
self.moneyborrowed.push(new MoneyBorrowedViewModel(self, money));
});
// holds the total moneyinvested count
self.TotalNumberOfMoneyborrowed(self.moneyborrowed().length);
// initialize the Money Requests and Offers available table
self.searchMoneyborrowed();
/* Read the payment plans for the frst request */
self.getPaymentPlan(self.moneyborrowed()[0].ORIG_ID);
self.lastDueDate(self.moneyborrowed()[0].Due);
});
So I was trying to use in the paymentPlanView model, a computed function to get two values and use them on a table like this
<tbody data-bind="foreach : paymentPlan" >
<tr>
<td class="text-center"><span data-bind="text: $data.duedate" ></span></td>
<td class="text-center"><span data-bind="text: $data.total_payment" ></span></td>
<td class="text-center"><span data-bind="text: $data.interest_payment" ></span></td>
<td class="text-center"><span data-bind="text: $data.capital_payment" ></span></td>
<td class="text-center"<span data-bind="text: $data.total_remaining" ></span></td>
</tr>
</tbody>
All the other values are shown in the table , only the total_remaining value I cannot see. So I am not sure why my computed value is not working. I have created the observables at the top like this.
self.paymentPlan = ko.observableArray();
So I need to know how can I put that computed value total_remaining, since I cannot see it now.
You need to remember that Knockout observables are functions. So to get the value of an observable, you need to "call" the observable. Your computed needs to be changed to:
self.total_remaining = ko.computed(function() {
var sum = 0;
sum += parseFloat(self.total_payment()) - parseFloat(self.total_paid());
return sum.toFixed(2);
});
Notice I'm using function call syntax for total_payment and total_paid.

x-editable Select in Meteor does not update value on clients

I want to use a select x-editable in my Meteor application. My goal is to assign users to groups. This should be reactive, so when you assign a user, other clients should see the changes. The current problem is that the assignment works (data-value changes), but only the user who made the change is able to see the new value.
Here is my code:
Template.userGroup.rendered = function() {
var groupId = this.data._id;
var sourceUsers = [];
Users.find().forEach(function(user) {
sourceUsers.push({value: user._id, text: user.username});
});
Tracker.autorun(function() {
$('.assign-user').editable("destroy").editable({
emptytext: "Empty",
source: sourceUsers,
success: function(response, result) {
if (result) {
Groups.update({_id: groupId}, {$set: {adminId: result}});
}
}
});
});
};
<template name="userGroup">
</template>
I already tried to "destroy" the stale x-editable and put it inside the Tracker.autorun function, but unfortunately, this does not work.
Any help would be greatly appreciated.
I don't use Tracker.autorun but I use x-editable for inline editing like this:
(also used it for group assigments - just like your case, but found it too clumsy on the UI side). Anyway, here's my code:
Template
<template name="profileName">
<td valign='top'>
<div id="profileNameID" class="editable" data-type="text" data-rows="1">{{profile.name}}</div>
</td>
</template>
And on the JS side
Template.profileName.rendered = function () {
var Users = Meteor.users;
var container, grabValue, editableColumns, mongoID,
_this = this;
var container = this.$('#profileNameID');
var editableColumns = container.size();
grabValue = function () {
var gValue = $.trim(container.html());
return gValue;
};
$.fn.editable.defaults.mode = 'inline';
return container.editable({
emptytext: 'Your name goes here',
success: function (response, newValue) {
var mongoID = removeInvisibleChars($(this).closest("tr").find(".mongoid").text());
var editedUser = _users.findOne({
_id: mongoID
});
Meteor.users.update(mongoID, {
$set: {
"profile.name": newValue
}
});
return container.data('editableContainer').formOptions.value = grabValue;
}
});
Update happens immediately on all subscribed authorized clients.

Categories

Resources