KnockoutJS - can't use "Slice" with ko.computed object - javascript

I'm trying to create pagination using knockoutjs-2.1.0, and I'm getting the following error:
Uncaught TypeError: Object function h(){if(0return i||e(),a.U.La(h),k} has no method 'slice'
I've narrowed the problem down to this: Apparently knockout doesn't like calling the "slice" method on an object which is created using ko.computed. My computed type is this:
this.contactsToShow = ko.computed(function() {
// Represents a filtered list of contacts
// i.e., only those matching the "typeToShow" condition
var desiredType = this.typeToShow();
if (desiredType == "all") {
return this.allContacts();
}
return ko.utils.arrayFilter(this.allContacts(), function(aContact) {
return aContact.contactType == desiredType;
});
}, this);
And it throws an error in when I'm setting the "showCurrentPage" property, here:
contactListView.showCurrentPage = ko.dependentObservable(function() {
if (this.currentPage() > this.totalPages()) {
this.currentPage(this.totalPages() - 1);
}
var startIndex = this.pageSize() * this.currentPage();
return this.contactsToShow.slice(startIndex, startIndex + this.pageSize());
}, contactListView);
However, if I use the original observableArray when setting showCurrentPage (the allContacts array), it works.
You can find the jsfiddle here: http://jsfiddle.net/mzalen/S74rJ/12/
I would really appreciate any advice on this issue, as it's driving me mad.

Common error with Knockout: this.contactsToShow becomes a function in your example and you must call it as a function:
return this.contactsToShow().slice(startIndex, startIndex + this.pageSize());

Related

Loop through an object if property does not always exist or is undefined

I want to build a table in Raect with a sorted list of watches of a certain ebay listing.I figured out that the problem is this line:
entriesObj[value][1][0].listingInfo[0].watchCount[0]
because sometimes listing don't have any watches at all and in this case value watchCount doesn't exist at all so I can't loop through it, although I tried to use conditional operator (and if else statements in many different ways) it still throws an error. First I created an object:
watcherCount = () => {
return (
this.state.itemList.reduce((watcherObject,item) => {
const watcherKey = item.itemId;
if (!watcherObject[watcherKey]) {
watcherObject[watcherKey] = [item];
} else {
watcherObject[watcherKey].push(item);
}
return watcherObject;
},{})
);
}
and now I am trying to move them to an array ([number of watches, title of listing, item id]) in order to sort them:
import React from 'react';
class Watches extends React.Component {
render () {
var entriesObj = Object.entries(this.props.watcherCount);
var sortable = [];
for (var value in entriesObj){
for (var value in entriesObj){
sortable.push([typeof entriesObj[value][1][0].listingInfo[0].watchCount[0] === "undefined" ? "-" : entriesObj[value][1][0].listingInfo[0].watchCount[0], entriesObj[value][1][0].title[0], entriesObj[value][0]]);
}
}
sortable.sort(function(a, b) {
return b[0] - a[0];
});
console.log(sortable);
//Output: Uncaught (in promise) TypeError: Cannot read property '0' of undefined
return <table></table>
}
}
export default Watches;
Do you know any other way to build this exact kind of array or how to solve the problem with missing property?
I Don't know if I fully understood the problem.
In cases with deep references, if I don't want or can't use any conditional checks I simply put the object path reference in a try catch (finally) block.
e.g. (untested though)
for (var value in entriesObj){
var val;
try {
// just make sure the only error that might be occuring
// here is an object reference error
// therefore the array push happens after the try catch block
val = entriesObj[value][1][0].listingInfo[0].watchCount[0], entriesObj[value][1][0].title[0], entriesObj[value][0]];
} catch(err) {
val = "-";
// log the error or maybe issue a warning since missing items
// is actually expected behaviour
} finally {
sortable.push(val);
}
}
Maybe it solves your problem.

Breeze JS - Extending model from object graph

Currently I am able to extend the breeze model entity type of my Product entity using the following code:
function registerProduct(metadataStore) {
function Product(){}
// description property
Object.defineProperty(Product.prototype,'description', {
// TODO: handle selected globalization language
get: function () {
return this.descripFr;
}
})
metadataStore.registerEntityTypeCtor('Product',Product);
}
The issue I am having is using a property from the entity graph (in this case codeligne) in an extended property like so:
Object.defineProperty(Product.prototype,'name', {
get: function () {
var codeligne = this.codeligne;
var name = codeligne.ligne + '-' + this.codeprod;
return name;
}
})
This throws an undefined exception for codeligne.ligne.
If I directly use the codeligne.ligne in an ng-repeat then the property is displayed properly so Breeze seems aware of it.
Any suggestions on how to use the codeligne graphed object when extending the model?
It is possible that the entity represented by the "ligne" navigation property isn't loaded yet. You should check that it contains a value before referencing its properties.
Object.defineProperty(Product.prototype, 'name', {
get: function () {
var codeligne = this.codeligne;
if (!codeligne) {
return null;
}
var name = codeligne.ligne + '-' + this.codeprod;
return name;
}
})

understanding the code from transit.js

I was just going through the source of transit.js and came across the following fucntion ::
$.cssHooks['transit:transform'] = {
// The getter returns a `Transform` object.
get: function(elem) {
return $(elem).data('transform') || new Transform();
},
// The setter accepts a `Transform` object or a string.
set: function(elem, v) {
var value = v;
if (!(value instanceof Transform)) {
value = new Transform(value);
}
// We've seen the 3D version of Scale() not work in Chrome when the
// element being scaled extends outside of the viewport. Thus, we're
// forcing Chrome to not use the 3d transforms as well. Not sure if
// translate is affectede, but not risking it. Detection code from
// http://davidwalsh.name/detecting-google-chrome-javascript
if (support.transform === 'WebkitTransform' && !isChrome) {
elem.style[support.transform] = value.toString(true);
} else {
elem.style[support.transform] = value.toString();
}
$(elem).data('transform', value);
}
};
I understand the latter part of the function, but its really hard to understand the initial part of the function, the function can be found on git too , HERE .
Initially I see this, $.cssHooks['transit:transform'] what is that line really saying?
After that we have the below line of code I.E. the getter and setter method,
set: function(elem, v) {
But who is passing the elem and v inside the function, I don't see anything being passed?
Read about cssHooks at jQuery cssHooks
Look at the source code (search for hooks.get and hooks.set)
.cssHooks is an array of objects that contains getter and setters tha will be executed by .css(). Thats all.
$.cssHooks['transit:transform'] = {set: function(elem,value){}, get: function(elem){}}
equal:
$.cssHooks['transit:transform'] = {};
$.cssHooks['transit:transform'].set = function(elem, value){};
$.cssHooks['transit:transform'].get = function(elem){};
$(element).css('transit:transform',value)
comes to:
$.cssHooks['transit:transform'].set(element,value)
$(element).css('transit:transform')
comes to:
$.cssHooks['transit:transform'].get(element)
$.cssHooks['transit:transform'] = {set:function(){}, get: function(){} }
{...} is an object creation.get and set not executed at this moment.
They created {set:function(){}, get: function(){} }
So. Simply: .css() will execute set and get functions for hooked property.
If you want to know how real getters and setters works:
Object.defineProperty()
In Javascript, you can add/access to a property with this syntax :
myObject.myProperty
or with this syntax :
myObject['myProperty']
This is the same result
So your line
$.cssHooks['transit:transform']
just mean that we want to store an object (code between {} in your original post) inside the 'transit:transform' property which is inside the cssHooks property which is inside the $ object
This is the same things :
$['cssHooks']['transit:transform']
The reason why they use the [''] syntax is that transit:transform contains the ':' char which is not allowed if you want to access it this way :
$.cssHooks.transit:transform //doesn't work
EDIT:
To answer to your second question, i don't know...the code you are showing is just the 'description' of the "transit:transform' property

javascript how to return a number from an object variable

So, I have a large object called con in that object, I have many variables, numbered sort of like an excel sheet, b19, b20, b21, etc.
I am trying to return a value from each one, but when I do a console log, It logs the entire function, not just the return.
Here's how the object is set up:
var con = {
b13: function(){
return 12600.535*Math.sqrt((con.b14+459.4)/459.4)
},
b14: function(){
return 20;
}
}
$(document).ready(function(){
console.log(con.b13);
});
This outputs this into the console:
function(){
return 12600.535*Math.sqrt((con.b14+459.4)/459.4)
}
So how do I format this so that it outputs the actual number in the equation?
You need to make b13 and b14 properties with a getter function:
var con = {};
Object.defineProperty(con, "b13", {
get: function() {
return 12600.535*Math.sqrt((con.b14+459.4)/459.4);
}
});
Object.defineProperty(con, "b14", {
get: function() { return 20; }
});
This will cause con.b13 and con.b14 to call the given functions, returning whatever the functions return.
Try console.log(con.b13()); . You are logging the function definition not executing it.
you don't define the properties as functions...
var con = {
b13: 239487,
b12: 923748
};
edit: if some properties need to be functions you have to call them e.g. con.b14(), not con.b14 as a property
You can simply use es5 getters/setters.
var con = {
get b13() {
return 12600.535*Math.sqrt((con.b14+459.4)/459.4);
},
get b14() {
return 20;
}
};
The problem is that your object's properties are functions, but you are trying to call them as if they were values.
For example, if you wanted correctly log con.b13's value to the console, you would need to change the command to:
console.log(con.b13());
What this does is get what con.b13 returns rather than what it is.
If you don't want to go through the hassle of adding a () next to every reference, you can modify the object and define getters like this:
var con = {
get b13() {
return 12600.535 * Math.sqrt((con.b14 + 459.4) / 459.4)
},
get b14() {
return 20;
}
}
If you define the object like this, your original command console.log(con.b13) will work as intended.

Trouble referencing variable in Collections.where method within render function

I have run into some trouble with a piece of backbone code. The code below relates to a render function. I can retrieve all the models. My trouble arises when I try to use the "Collections.where" method at line marked number #1. As you can see, I have passed an object literal into the render function but for some reason I am unable to reference it within the customers.where method on line #1. When I give this method a literal number like 45 it works. Is there some way around this so I can pass the variable reference in?
Thanks alot
render: function(options) {
var that = this;
if (options.id) {
var customers = new Customers();
customers.fetch({
success: function (customers) {
/* #1 --> */ var musketeers = customers.where({musketeerId: options.id});
console.log(musketeers.length) //doesn't work as options.id is failing on last line
var template = _.template($('#customer-list-template').html(), {
customers: customers.models
});
that.$el.html(template);
console.log(customers.models);
}
});
} else {
var template = _.template($('#customer-list-template').html(), {});
that.$el.html(template);
}
}
Although it isn't explicitly documented, Collection#where uses strict equality (===) when searching. From the fine source code:
where: function(attrs, first) {
if (_.isEmpty(attrs)) return first ? void 0 : [];
return this[first ? 'find' : 'filter'](function(model) {
for (var key in attrs) {
if (attrs[key] !== model.get(key)) return false;
}
return true;
});
},
note the attrs[key] !== model.get(key) inside the callback function, that won't consider 10 (a probable id value) and '10' (a probable search value extracted from an <input>) to be a match. That means that:
customers.where({musketeerId: 10});
might find something whereas:
customers.where({musketeerId: '10'});
won't.
You can get around this sort of thing with parseInt:
// Way off where you extract values from the `<input>`...
options.id = parseInt($input.val(), 10);

Categories