Knockout Check If Existing in observableArray before Push - javascript

I am new to Knockout and I have a little problem stopping me from completing my simple project.I have an observableArray called loanDeductions that I display in a table with foreach binding. I have another observableArray called loanDeductionsList which is also from the json data of my first observableArray, I used it in my drop down list which when a value is selected, it will push the selected data to my table. If it didn't make sense as I cannot really explain it clearly, this is my javascript file:
var deductionLine = function (deductionID, deductionName, amount) {
self = this;
self.deductionID = ko.observable(deductionID);
self.deductionName = ko.observable(deductionName);
self.amount = ko.observable(formatCurrency(amount));
};
function LoanDeductions(deductions) {
var self = this;
self.loanDeductions = ko.observableArray(ko.utils.arrayMap(deductions, function (deduction) {
return new deductionLine(deduction.deductionID, deduction.deductionName, deduction.amount)
}));
self.loanDeductionsList = ko.observableArray(ko.utils.arrayMap(deductions, function (deduction) {
return new deductionLine(deduction.deductionID, deduction.deductionName, deduction.amount)
}));
self.selectedDeduction = ko.observable();
self.selectedDeduction.subscribe(function (data) {
self.loanDeductions.push({
deductionID: data.deductionID,
deductionName: data.deductionName,
amount: data.amount,
});
});
}
Can you help me find a way to make my function selectedDeduction.subscribe() push the data ONLY when the item to be pushed is not existing in my loanDeductions observableArray.
Any help will be greatly appreciated. Thank you!
I am somewhat aware that the way I populate my dropdown list may o may not be the best way to do it, I am open to suggestion of a better way and rewrite my program.

just to share what I did I added this line in my selectedDeduction.subscribe():
self.selectedDeduction.subscribe(function (data) {
var match = ko.utils.arrayFirst(self.loanDeductions(), function(deduction) {
return deduction.deductionID() === data.deductionID();
});
if (match) {
alert(data.deductionName() + ' already exists!');
} else {
self.loanDeductions.push({
deductionID: data.deductionID,
deductionName: data.deductionName,
amount: data.amount,
});
}
});

Related

I want to delete multiple CRM records from Dynamics with Xrm.WebApi.online.executeMultiple

Multiple entity records have to be deleted in one call instead of multiple callbacks so trying to use Xrm.WebApi.online.executeMultiple to delete records. but the code written below is not working. Any help will be appreciated.
for (var i=0; i<Checkbox.length; i++)
{
if(Checkbox[i].checked)
{
var id = Checkbox[i].value;// GUID of the record to be deleted
Checkbox[i].checked = false;
DeleteRequests[i]={};
DeleteRequests[i].getMetadata = function(){
return{
boundParameter: undefined,
operationType: 2,
operationName: "Delete",
parameterTypes: {
}
}
}
DeleteRequests[i].etn="cme_entity";
DeleteRequests[i].payload=id;
}
}
window.parent.Xrm.WebApi.online.executeMultiple(DeleteRequests).then(
function (results) {alert("Success");},
function (error) {alert("Failed");});
Getting weird error that this operation could not be processed. Please contact Microsoft.
The issue has to do with how you are constructing the delete request objects. You need to declare a function that sets up the getMetadata function and the required entityReference object.
I've tested the below solution and it works.
var Sdk = window.Sdk || {};
Sdk.DeleteRequest = function (entityReference) {
this.entityReference = entityReference;
this.getMetadata = function () {
return {
boundParameter: null,
parameterTypes: {},
operationType: 2,
operationName: "Delete",
};
};
};
for (var i = 0; i < Checkbox.length; i++) {
if (Checkbox[i].checked) {
var id = Checkbox[i].value;
Checkbox[i].checked = false;
DeleteRequests[i] = new Sdk.DeleteRequest({ entityType: "account", id: id });
}
}
window.parent.Xrm.WebApi.online.executeMultiple(DeleteRequests).then(
function (results) { alert("Success"); },
function (error) { alert("Failed"); });
Unfortunately CRUD operations with Xrm.WebApi.online.execute and Xrm.WebApi.online.executeMultiple are not very well documented. I've written a blog post with some code samples.
The important parts are the declaration of the Sdk.DeleteRequest function as a property on window and instantiating a request object using new Sdk.DeleteRequest(). I experimented a little and determined that just simply creating a request object like you were doing before, even with the right attributes does not work either.
Hope this helps! :)

angular().service() wont get a update in the object I pass as parameter

Well fist time here, so sorry for the mess or the long text.
I pass $scope.alertsensorconfigs as tableData to my service, and wen I delete a item, my $scope.alertsensorconfigs changes but wen It try to reload the table I see that tableData had not changed.
Detailed explanation:
I have a site that uses NgTable to create a lot of tables in different pages, but all the logic to convert and filter the data that I want to show in the page was coded in the pages and it repeated a lot of times but it was working, so i decided to thy make a service that do all that.
So my problem is, I created the service, it i almost all working like before, but I notices that wen I delete a item from the table, it deletes the data but keep showing it on the table until I reload the page.
I notice that it is because even that my object on the page have changed after delete, wen it is inside my service the object apear to be the unchanged one, since I passed my object as parameter to my service i took it wold pass like a reference to the object and wen it changes on the page it wold apear changed in my service, but looks like it is not the case, it looks like wen it calls for the fist time my service it makes a copy of my object and wen it calls again it wont get the updated one.
My page code.
$scope.funcFilter = function(pfilter){
return function (item) {
return item.name.toUpperCase().indexOf(pfilter) >= 0
||
item.criticality1.toString().toUpperCase().indexOf(pfilter) >= 0
||
item.criticality2.toString().toUpperCase().indexOf(pfilter) >= 0
|| $filter('translate')
(item.active.toString().toUpperCase()).indexOf(pfilter) >= 0;
}
}
$scope.searchTable = {filter: ""};
$scope.tableParams =
NgTableDataService.getGenericTableParams($scope.alertsensorconfigs,
$scope.funcFilter, $scope.searchTable.filter)
Delete function in my page:
AlertSensorConfig.remove({id: obj.id}, function () {
$scope.alertsensorconfigs.splice($scope.alertsensorconfigs.indexOf(obj), 1);
$scope.tableParams.reload().then(function(data) {
if (data.length === 0 && $scope.tableParams.total() > 0) {
$scope.tableParams.page($scope.tableParams.page() - 1);
$scope.tableParams.reload();
}
});
},
My service:
angular.module('control-room').service('NgTableDataService',
function ($filter, NgTableParams, Session) {
var session = Session.get();
this.getGenericTableParams = function(tableData, funcFilter, searchTableFilter){
return new NgTableParams({
count: session.user.tablePagination,
filter: searchTableFilter
}, {
counts: rowsPerPageTemplate,
getData: function (params) {
if (params.filter() == ''){
var pfilter = '';
}else{
var pfilter = params.filter().filter.toUpperCase();
}
let filteredData = params.filter() ? $filter('filter')(tableData, funcFilter(pfilter)) : tableData;
if (!!filteredData && filteredData.length >= 0) {
params.total(filteredData.length);
var rowsPerPageTemplateWithAllData = rowsPerPageTemplate.slice();
var isFound = rowsPerPageTemplateWithAllData.some(function (element) {
return element === filteredData.length;
});
params.settings().counts = rowsPerPageTemplateWithAllData.filter(item=>item<filteredData.length)
if (filteredData.length >= 5){
params.settings().counts.push(filteredData.length);
}
rowsPerPageTemplateWithAllData.push(filteredData.length + (isFound ? 1 : 0));
if (session.user.tablePagination >= params.settings().counts[params.settings().counts.length-1]){
params.settings().count = params.settings().counts[params.settings().counts.length-1];
}else{
params.settings().count = session.user.tablePagination;
}
if (params.total() <= params.count()) {
params.page(1);
}
var x = $filter('orderBy')(filteredData, params.orderBy());
var y = x.slice((params.page() - 1) * params.count(), params.page() * params.count());
return y;
} else {
params.settings().counts = [];
return null;
}
}
});
};
And the ng-table function that reload the table after delete:
this.reload = function() {
var self = this,
pData = null;
settings.$loading = true;
prevParamsMemento = angular.copy(createComparableParams());
isCommittedDataset = true;
if (self.hasGroup()) {
pData = runInterceptorPipeline($q.when(settings.getGroups(self)));
} else {
pData = runInterceptorPipeline($q.when(settings.getData(self)));
}
log('ngTable: reload data');
var oldData = self.data;
return pData.then(function(data) {
settings.$loading = false;
errParamsMemento = null;
self.data = data;
event even when data === oldData
ngTableEventsChannel.publishAfterReloadData(self, data, oldData);
self.reloadPages();
return data;
}).catch(function(reason){
errParamsMemento = prevParamsMemento;
// "rethrow"
return $q.reject(reason);
});
};
there is some way to make sure the object I pas as parameter to my service is updated every time I call it, like some binding?
I think i manage to solve it.
The NgTable have his own reload(), but it wasn't working because what it does is, get the current filteredData and replace with the one tableData, but the tableData on my service was only set wen it was called the fist time and wasn't getting updated wen I updated the $scope.alertsensorconfigs.
So what I manage to do after a lot of headache, was to create in my service:
A var serviceTableData that receives the $scope.alertsensorconfigs wen the service is called so it is global in my service.
And my own reload() function that I replaced in every place that my controller used the NgTable reload().
My service reload() wen called receives as parameter from the controller the $scope.alertsensorconfigs after the controller delete or edit the item, then it will set the serviceTableData to the updated data received as param and then calls the NgTable reload().
So it ended like this:
angular.module().service('NgTableDataService',
function ($filter, NgTableParams, Session, MY_CONSTANTS) {
var session = Session.get();
var serviceTableParam = null;
var serviceTableData = null;
this.reloadTableData = function (tableDataAtt){
serviceTableData = tableDataAtt;
serviceTableParam.reload().then(function(data) {
if (data.length === 0 && serviceTableData.total() > 0) {
serviceTableParam.page(serviceTableParam.page() - 1);
serviceTableParam.reload();
}
return this.tableData = tableDataAtt;
});
};
this.getGenericTableParams = function(tableData, searchTableFilter, funcFilter){
serviceTableData = tableData;
return serviceTableParam = new NgTableParams({
// etc...
Edit : I misunderstood the question
According to your comment what you want is to update a variable in your service and retrieve it later.
What you can do is :
In your service
angular
.module('app.core')
.factory('', dataservice);
dataservice.$inject = ['$http'];
function dataservice($http) {
return {
myFunction: yourServiceFunction,
myData: myData
};
var myData = [];
function yourServiceFunction(tableData) {
// DO SOMETHING
myData = tableData;
// DO SOMETHING
}
}
Like this you can access to myData in your service or in your controller which is updated in your function with the value of tableData that you passed when you called your function.
And if you want to update myData in your service everytime $scope.alertsensorconfigs changes, add a $watch to this variable and create a function in your service who is called whenever your $scope value change and which simply update myData in your service.
I hope that I answered to the right question this time :)
.
.
.
Here after : old response which do not answer to the question
there is some way to make sure the object I pas as parameter to my service is updated every time I call it, like some binding?
Yes.
I am sorry to not answer with your code but it is a bit hard to get into it.
The simpliest way is to do something like this :
$scope.alertsensorconfigs =
yourService.yourMethod($scope.alertsensorconfigs, param2, param3).tableData;
While your services' method does something like :
yourMethod = function (tableData, param2, param3) {
// DO SOMETHING
return { tableData : tableDataAfterModification, elem2 : 'elem2', elem3 : 'elem3' };
};

Pushing object to Array makes parameter empty

I'm trying to solve problem of merging two arrays of objects, so I wrote a pretty simple function
function mergeShowtimes(movies) {
var existing_halls = [];
return movies.reduce(function(acc, movie) {
var movies_with_hallid,
movies_seats;
if (existing_halls.indexOf(movie.hallId) === -1) {
movies_with_hallid = _.filter(movies, function(filter_movie) {
return movie.hallId === filter_movie.hallId;
});
movies_seats = _.map(movies_with_hallid, 'seats');
movie.seats = _.union.apply(this, movies_seats);
acc.push(movie);
existing_halls.push(movie.hallId);
}
return acc;
}, []);
}
problem is, whenever I check the value of movie and movie.seats, field 'seats' in movie is empty, but movie.seats is not, for some reason
If I'll remove acc.push(movie); everything will start working as planned
What am I doing wrong?
Thanks for any feedback!

How to assign array of object to dropdown in angularjs?

Hi I am developing web application in angularjs. I have one html form with several drop downs. I am making api calls to fill data to drop down. Instead of making separate call in one call i am getting all data required to bind all drop downs.
Below is my sample data.
{"status":"Success","msg":"Success","code":"200","data":{"Education":[{"ID":1,"Education":"btech"},{"ID":2,"Education":"Bcom"},{"ID":3,"Education":"BA"},{"ID":6,"Education":"PU"}],"MaritalStatus":[{"ID":1,"MaritalStatus":"sinle"},{"ID":2,"MaritalStatus":"married"}]}
I am trying to bind it to drop down as below.
var martialstatus = new Array();
var Education = new Array();
$http.get(baseurl + 'api' + '/Customer/' + 'PersonalInfoMasters').success(function (data) {
$.map(data.data, function (item) {
Education.push(item[0]);
});
console.log(Education);
}).error(function (status) {
});
Abobe piece of code gets me first item from the each object like first item from education,martial status etc. I would like to bind education object to education array. May i know where i am missing any line of code? Any help would be appreciated.
You don't seem to do any kind of mapping from the original result, so the following would suffice:
Education = data.data.Education;
Note:
The item[0] looks strange - are you trying to achieve something with that ?
I would use lowercase for the name of the variable.
Try something like this:
var MaritalStatus = new Array();
var Education = new Array();
$http.get(baseurl + 'api' + '/Customer/' + 'PersonalInfoMasters').success(function (data) {
$.map(data.data.Education, function (item) {
Education.push(item);
});
$.map(data.data.MaritalStatus, function (item) {
MaritalStatus.push(item);
});
}).error(function (error) {
// handle API errors
});
If you do not even need to format the output, you can simply re-assign the original value of your variable.
$http.get(baseurl + 'api' + '/Customer/' + 'PersonalInfoMasters').success(function (data) {
Education = data.data.Education;
MaritalStatus = data.data.MaritalStatus;
}).error(function (error) {
// handle API errors
});
You can do it this way:
var martialstatus = new Array();
var Education = [];
$http.get(baseurl + 'api' + '/Customer/' + 'PersonalInfoMasters').success(function(data) {
$.map(data.data.Education, function(item) {
Education.push(item);
});
}).error(function(status) {
});
You just need to push item instead of item[0] in the .map() method so it takes the whole Education object and push it in your array.
Otherwise you can just use with no need to use the $.map():
Education = data.data.Education
Shouldn't it be more like:
$.map(data.data.Education, function (item) {
Education.push(item[0]);
});
?

Access variable from another JS file

I have two JS files, base_player.js and station.js.
I have some logic in base_player.js that needs access to a value that comes from station.js. While the var is 'global', it is wrapped in a namepace mm.Station. The value I need is a UUID of a selected station:
mm.Station = function($el) {
"use strict";
if (_.isUndefined($el)) {
return;
}
var self = mm.EventEmitter();
var $actions;
self.uuid = $el.attr("data-uuid");
.........
I feed any selected station with songs in batches at a certain point in a queue. This logic all happens in base_player.js.
I want to get the UUID from station.js to use in this GET in base_player.js:
mm.BasePlayer = function ($el) {
........
function feedSelectedStation(uuid) {
if(_.isUndefined(uuid)){
return false;
}
$.get('/feed-station/' + uuid)
.done(function (data) {
console.log('feedSelectedStation');
if(!_.has(data, "list")){ return; }
self.queue = self.queue.concat(data.list);
});
}
.........
I don't write much Javascript so I'm a bit unsure how to achieve this. Any pointers appreciated.

Categories

Resources