Rickshaw.Graph.RangeSlider TypeError: $(element).slider is not a function - rangeslider

I have this error:
TypeError: $(element).slider is not a function
with the following script:
Rickshaw.namespace('Rickshaw.Graph.RangeSlider');
Rickshaw.Graph.RangeSlider = function(args) {
var element = this.element = args.element;
var graph = this.graph = args.graph;
$( function() {
$(element).slider( {
range: true,
min: graph.dataDomain()[0],
max: graph.dataDomain()[1],
values: [
graph.dataDomain()[0],
graph.dataDomain()[1]
],
slide: function( event, ui ) {
graph.window.xMin = ui.values[0];
graph.window.xMax = ui.values[1];
graph.update();
// if we're at an extreme, stick there
if (graph.dataDomain()[0] == ui.values[0]) {
graph.window.xMin = undefined;
}
if (graph.dataDomain()[1] == ui.values[1]) {
graph.window.xMax = undefined;
}
}
} );
} );
$(element)[0].style.width = graph.width + 'px';
graph.onUpdate( function() {
var values = $(element).slider('option', 'values');
$(element).slider('option', 'min', graph.dataDomain()[0]);
$(element).slider('option', 'max', graph.dataDomain()[1]);
if (graph.window.xMin == undefined) {
values[0] = graph.dataDomain()[0];
}
if (graph.window.xMax == undefined) {
values[1] = graph.dataDomain()[1];
}
$(element).slider('option', 'values', values);
} );
};
From the following page:
https://github.com/shutterstock/rickshaw/blob/master/src/js/Rickshaw.Graph.RangeSlider.js
The javascript debugger show me this line: slide: function( event, ui ) {
Can you show me a way to resolve my problem. Thanks you!

You should import jqueryui before using the slider.
http://jqueryui.com/slider/

Related

Other product variant is disabled and I can not select it for 2 products (JS)

I am a coding beginner and I am building a store. My problem is that I have a product in different fabrics. Now I can only select one fabric type and the other is disabled and I can not select no matter what I do. Perfect would be if I select the fabric type, the associated products are displayed.
That what i mean
/*============================================================================
Dynamic variant availability
- To disable, set dynamicVariantsEnable to false in theme.liquid
==============================================================================*/
setCurrentVariantAvailability: function(variant) {
var valuesToEnable = {
option1: [],
option2: [],
option3: []
};
// Disable all options to start
this.disableVariantGroup($(selectors.formContainer, this.$container).find('.variant-input-wrap'));
// Combine all available variants
var availableVariants = this.variantsObject.filter(function(el) {
if (variant.id === el.id) {
return false;
}
// Option 1
if (variant.option2 === el.option2 && variant.option3 === el.option3) {
return true;
}
// Option 2
if (variant.option1 === el.option1 && variant.option3 === el.option3) {
return true;
}
// Option 3
if (variant.option1 === el.option1 && variant.option2 === el.option2) {
return true;
}
});
// IE11 can't handle shortform of {variant} so extra step is needed
var variantObject = {
variant: variant
};
availableVariants = Object.assign({}, variantObject, availableVariants);
// Loop through each available variant to gather variant values
for (var property in availableVariants) {
if (availableVariants.hasOwnProperty(property)) {
var item = availableVariants[property];
var option1 = item.option1;
var option2 = item.option2;
var option3 = item.option3;
if (option1) {
if (valuesToEnable.option1.indexOf(option1) === -1) {
valuesToEnable.option1.push(option1);
}
}
if (option2) {
if (valuesToEnable.option2.indexOf(option2) === -1) {
valuesToEnable.option2.push(option2);
}
}
if (option3) {
if (valuesToEnable.option3.indexOf(option3) === -1) {
valuesToEnable.option3.push(option3);
}
}
}
}
// Have values to enable, separated by option index
if (valuesToEnable.option1.length) {
this.enableVariantOptionByValue(valuesToEnable.option1, 'option1');
}
if (valuesToEnable.option2.length) {
this.enableVariantOptionByValue(valuesToEnable.option2, 'option2');
}
if (valuesToEnable.option3.length) {
this.enableVariantOptionByValue(valuesToEnable.option3, 'option3');
}
},
updateVariantAvailability: function(evt, value, index) {
if (value && index) {
var newVal = value;
var optionIndex = index;
} else {
var $el = $(evt.currentTarget);
var newVal = $el.val() ? $el.val() : evt.currentTarget.value;
var optionIndex = $el.data('index');
}
var variants = this.variantsObject.filter(function(el) {
return el[optionIndex] === newVal;
});
// Disable all buttons/dropdown options that aren't the current index
$(selectors.formContainer, this.$container).find('.variant-input-wrap').each(function(index, el) {
var $group = $(el);
var currentOptionIndex = $group.data('index');
if (currentOptionIndex !== optionIndex) {
// Disable all options as a starting point
this.disableVariantGroup($group);
// Loop through legit available options and enable
for (var i = 0; i < variants.length; i++) {
this.enableVariantOption($group, variants[i][currentOptionIndex]);
}
}
}.bind(this));
},
disableVariantGroup: function($group) {
if (this.settings.variantType === 'dropdown') {
$group.find('option').prop('disabled', true)
} else {
$group.find('input').prop('disabled', true);
$group.find('label').toggleClass('disabled', true);
}
},
enableVariantOptionByValue: function(array, index) {
var $group = $(selectors.formContainer, this.$container).find('.variant-input-wrap[data-index="'+ index +'"]');
for (var i = 0; i < array.length; i++) {
this.enableVariantOption($group, array[i]);
}
},
enableVariantOption: function($group, value) {
// Selecting by value so escape it
value = value.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/#])/g,'\\$1');
if (this.settings.variantType === 'dropdown') {
$group.find('option[value="'+ value +'"]').prop('disabled', false);
} else {
var $buttonGroup = $group.find('.variant-input[data-value="'+ value +'"]');
$buttonGroup.find('input').prop('disabled', false);
$buttonGroup.find('label').toggleClass('disabled', false);
}
},
Have already tried various things, but not come to the desired result, even disabling the function ensures that everything is displayed and also clickable.
I hope you can help me.
Best Regards

Filter keys in Object

I am trying to implement a simple extraction function that connects to the Poloniex.returnTicker endpoint and, extract the 'last' key for any currency pairs starting with 'BTC'. There are a number of keys starting with 'BTC' but, my extraction function is stopping after returning exactly one key. I am mapping the extracted data in an object in the following manner:
extracted = {
BTC: {
STR: {
lastPrice: price
},
ETH: {
lastPrice: price
}, //...
}, //...
}
I wrote the following function for extraction:
module.exports = {
extractData: (tickerdata, marker) => {
if(!!!marker){
marker = 'BTC';
}
return new Promise((res, rej) => {
let currentBuffer = {};
Object.keys(tickerdata)
.filter((key) => {
return key.startsWith(marker);
})
.forEach((filtKey) => {
let c = filtKey.split('_'),
src = c[0],
dst = c[1];
currentBuffer[src] = {};
Object.keys(tickerdata[filtKey])
.forEach((entry) => {
if(!!!(dst in currentBuffer[src])){
currentBuffer[src][dst] = {};
}
if(entry == 'last'){
currentBuffer[src][dst]['lastPrice'] = tickerdata[filtKey][entry];
}
});
});
res(currentBuffer);
});
},//... rest of the module exports
For reference, each call to return ticker endpoint returns data in the following format: Poloniex API. Look at returnTicker endpoint for example.
I am guessing that there is a logical error in the extraction function but, I am not sure where.
UPDATE
What about this code?
module.exports = {
extractData: (tickerdata, marker) =>
Object.keys(tickerdata)
.map(x => x.split('_'))
.filter(x => x && x[0] == (marker || 'BTC') && x[1])
.map(x => x[0] + '_' + x[1])
.map(x => [x, Object.keys(tickerdata[x])
.map(y => [y, tickerdata[x][y].lastPrice])]);
and usage:
const extracted = {
ETH_STR: {
BTC: {
lastPrice: 1
}
},
BTC_ETH: {
STR: {
lastPrice: 1
}
},
BTC_STR: {
STR: {
lastPrice: 1
},
ETH: {
lastPrice: 2
}, //...
}, //...
};
const result = extractData(extracted, 'BTC');
console.log(JSON.stringify(result));
with result
[["BTC_ETH",[["STR",1]]],["BTC_STR",[["STR",1],["ETH",2]]]]
I have tinkered around with my code and, finally was able to make it work. Besides adding more code for extracting data from the API response object, tickerdata, I have changed the promise to return instead of resolve. This ensured that the flow remains in proper sequence. I used a then clause on the promise to retrieve the extracted values (named buff). Here is the full working code:
`module.exports = {
extractData: (markers) => {
// extracts the data for all markers which, are a comma separated string of base currencies
return new Promise((res, rej) => {
markers = (!!!(markers) ? 'USDT,BTC' : markers)
polinst.returnTicker()
.then((tickerdata) => {
let buff = {};
markers.split(',').forEach((marker) => {
Object.keys(tickerdata)
.filter((key) => {
return key.startsWith(marker);
})
.forEach((fkey) => {
let c = fkey.split('_'),
src = c[0],
dst = c[1];
buff[src] = (!!!(buff[src]) ? {} : buff[src]);
buff[src][dst] = (!!!(buff[src][dst]) ? {} : buff[src][dst]);
Object.keys(tickerdata[fkey])
.forEach((k) => {
if(k == 'last'){
buff[src][dst]['lastPrice'] = tickerdata[fkey][k];
}
else if(k == 'quoteVolume'){
buff[src][dst]['volume'] = tickerdata[fkey][k];
}
else if(k == 'lowestAsk'){
buff[src][dst]['ask'] = tickerdata[fkey][k];
}
else if(k == 'highestBid'){
buff[src][dst]['highestBid'] = tickerdata[fkey][k];
}
});
});
});
return buff;
}).then((d)=>{
res(d);
}).catch((err)=>{
console.log(err);
});
});
},
};`

Using Babel to Get ApolloClient to ES5 CommonJS Module Format for Node Environment

Using Babel to Get ApolloClient to ES5 CommonJS Module Format
Im trying to use Babel to get the apollo-client module to work as ES5 in a non-browser, node environment. I've gone through step below which always give me the same result. Im trying to figure out if that result is right result for a node environment. When I import the babel processed documents into my project and call a method that should be exported, im getting, cannot find module. For context, the project is a fusetools.com demo. Fusetools does not support ES2015 Promises so the idea is that with the babel es2015 preset, it should work. I'm mostly chasing this down to learn something but it would be great if I could get it to work. Any comments on an easier way to do this, now that I understand it better, would be greatly appreciated. The project where I babeled the code can be found here. The fusetools project where i used the transformed code is here.
The error I get is :
LOG: Error: JavaScript error in MainView.ux line 9: Name: Fuse.Scripting.Error
Error message: require(): module not found: js/apollo-client/ApolloClient.js
File name: MainView.ux
Line number: 9
Source line: var ApolloClient = require('js/apollo-client/ApolloClient.js');
This is the code im trying to reach:
```
"use strict";
var networkInterface_1 = require('./transport/networkInterface');
var isUndefined = require('lodash.isundefined');
var assign = require('lodash.assign');
var isString = require('lodash.isstring');
var store_1 = require('./store');
var QueryManager_1 = require('./core/QueryManager');
var storeUtils_1 = require('./data/storeUtils');
var fragments_1 = require('./fragments');
var getFromAST_1 = require('./queries/getFromAST');
var DEFAULT_REDUX_ROOT_KEY = 'apollo';
function defaultReduxRootSelector(state) {
return state[DEFAULT_REDUX_ROOT_KEY];
}
var ApolloClient = function () {
function ApolloClient(_a) {
var _this = this;
var _b = _a === void 0 ? {} : _a,
networkInterface = _b.networkInterface,
reduxRootKey = _b.reduxRootKey,
reduxRootSelector = _b.reduxRootSelector,
initialState = _b.initialState,
dataIdFromObject = _b.dataIdFromObject,
resultTransformer = _b.resultTransformer,
resultComparator = _b.resultComparator,
_c = _b.ssrMode,
ssrMode = _c === void 0 ? false : _c,
_d = _b.ssrForceFetchDelay,
ssrForceFetchDelay = _d === void 0 ? 0 : _d,
_e = _b.mutationBehaviorReducers,
mutationBehaviorReducers = _e === void 0 ? {} : _e,
_f = _b.addTypename,
addTypename = _f === void 0 ? true : _f,
queryTransformer = _b.queryTransformer;
this.middleware = function () {
return function (store) {
_this.setStore(store);
return function (next) {
return function (action) {
var returnValue = next(action);
_this.queryManager.broadcastNewStore(store.getState());
return returnValue;
};
};
};
};
if (reduxRootKey && reduxRootSelector) {
throw new Error('Both "reduxRootKey" and "reduxRootSelector" are configured, but only one of two is allowed.');
}
if (reduxRootKey) {
console.warn('"reduxRootKey" option is deprecated and might be removed in the upcoming versions, ' + 'please use the "reduxRootSelector" instead.');
this.reduxRootKey = reduxRootKey;
}
if (queryTransformer) {
throw new Error('queryTransformer option no longer supported in Apollo Client 0.5. ' + 'Instead, there is a new "addTypename" option, which is on by default.');
}
if (!reduxRootSelector && reduxRootKey) {
this.reduxRootSelector = function (state) {
return state[reduxRootKey];
};
} else if (isString(reduxRootSelector)) {
this.reduxRootKey = reduxRootSelector;
this.reduxRootSelector = function (state) {
return state[reduxRootSelector];
};
} else if (typeof reduxRootSelector === 'function') {
this.reduxRootSelector = reduxRootSelector;
} else {
this.reduxRootSelector = null;
}
this.initialState = initialState ? initialState : {};
this.networkInterface = networkInterface ? networkInterface : networkInterface_1.createNetworkInterface({ uri: '/graphql' });
this.addTypename = addTypename;
this.resultTransformer = resultTransformer;
this.resultComparator = resultComparator;
this.shouldForceFetch = !(ssrMode || ssrForceFetchDelay > 0);
this.dataId = dataIdFromObject;
this.fieldWithArgs = storeUtils_1.storeKeyNameFromFieldNameAndArgs;
if (ssrForceFetchDelay) {
setTimeout(function () {
return _this.shouldForceFetch = true;
}, ssrForceFetchDelay);
}
this.reducerConfig = {
dataIdFromObject: dataIdFromObject,
mutationBehaviorReducers: mutationBehaviorReducers
};
this.watchQuery = this.watchQuery.bind(this);
this.query = this.query.bind(this);
this.mutate = this.mutate.bind(this);
this.setStore = this.setStore.bind(this);
this.resetStore = this.resetStore.bind(this);
}
ApolloClient.prototype.watchQuery = function (options) {
this.initStore();
if (!this.shouldForceFetch && options.forceFetch) {
options = assign({}, options, {
forceFetch: false
});
}
fragments_1.createFragment(options.query);
var fullDocument = getFromAST_1.addFragmentsToDocument(options.query, options.fragments);
var realOptions = Object.assign({}, options, {
query: fullDocument
});
delete realOptions.fragments;
return this.queryManager.watchQuery(realOptions);
};
;
ApolloClient.prototype.query = function (options) {
this.initStore();
if (!this.shouldForceFetch && options.forceFetch) {
options = assign({}, options, {
forceFetch: false
});
}
fragments_1.createFragment(options.query);
var fullDocument = getFromAST_1.addFragmentsToDocument(options.query, options.fragments);
var realOptions = Object.assign({}, options, {
query: fullDocument
});
delete realOptions.fragments;
return this.queryManager.query(realOptions);
};
;
ApolloClient.prototype.mutate = function (options) {
this.initStore();
var fullDocument = getFromAST_1.addFragmentsToDocument(options.mutation, options.fragments);
var realOptions = Object.assign({}, options, {
mutation: fullDocument
});
delete realOptions.fragments;
return this.queryManager.mutate(realOptions);
};
;
ApolloClient.prototype.subscribe = function (options) {
this.initStore();
var fullDocument = getFromAST_1.addFragmentsToDocument(options.query, options.fragments);
var realOptions = Object.assign({}, options, {
document: fullDocument
});
delete realOptions.fragments;
delete realOptions.query;
return this.queryManager.startGraphQLSubscription(realOptions);
};
ApolloClient.prototype.reducer = function () {
return store_1.createApolloReducer(this.reducerConfig);
};
ApolloClient.prototype.initStore = function () {
if (this.store) {
return;
}
if (this.reduxRootSelector) {
throw new Error('Cannot initialize the store because "reduxRootSelector" or "reduxRootKey" is provided. ' + 'They should only be used when the store is created outside of the client. ' + 'This may lead to unexpected results when querying the store internally. ' + "Please remove that option from ApolloClient constructor.");
}
this.setStore(store_1.createApolloStore({
reduxRootKey: DEFAULT_REDUX_ROOT_KEY,
initialState: this.initialState,
config: this.reducerConfig
}));
this.reduxRootKey = DEFAULT_REDUX_ROOT_KEY;
};
;
ApolloClient.prototype.resetStore = function () {
this.queryManager.resetStore();
};
;
ApolloClient.prototype.setStore = function (store) {
var reduxRootSelector;
if (this.reduxRootSelector) {
reduxRootSelector = this.reduxRootSelector;
} else {
reduxRootSelector = defaultReduxRootSelector;
this.reduxRootKey = DEFAULT_REDUX_ROOT_KEY;
}
if (isUndefined(reduxRootSelector(store.getState()))) {
throw new Error('Existing store does not use apolloReducer. Please make sure the store ' + 'is properly configured and "reduxRootSelector" is correctly specified.');
}
this.store = store;
this.queryManager = new QueryManager_1.QueryManager({
networkInterface: this.networkInterface,
reduxRootSelector: reduxRootSelector,
store: store,
addTypename: this.addTypename,
resultTransformer: this.resultTransformer,
resultComparator: this.resultComparator,
reducerConfig: this.reducerConfig
});
};
;
return ApolloClient;
}();
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = ApolloClient;
//# sourceMappingURL=ApolloClient.js.map
```
Any and all comments I might learn from are appreciated. Thank you.
One way to do this would be to use webpack like this:
const webpack = require('webpack');
const path = require('path');
module.exports = {
// watch: true,
entry: {
ApolloClient: './config/ApolloClient.js',
createNetworkInterface: './config/createNetworkInterface.js',
Redux: './config/Redux.js',
},
output: {
path: path.join(__dirname, 'build/Libs'),
filename: '[name].js',
library: '[name]',
libraryTarget: 'commonjs',
},
module: {
rules: [
{
use: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
}),
],
};
Then in config directory you could have:
/* ApolloClient.js */
import { ApolloClient } from 'apollo-client';
export default ApolloClient;
and
/* createNetworkInterface.js */
import { createNetworkInterface } from 'apollo-client/transport/networkInterface';
export default createNetworkInterface;
plus if you want to have Redux as well:
/* Redux.js */
import * as Redux from 'redux';
export default Redux;
However I was not able to get gql done this way and had to use bolav's fusepm.
Which you would use exactly as bolav has mention, first install it globally:
npm install -G fusepm and then fusepm npm graphql-tag
Once you have all these in place you can require them as follow:
var Redux = require('build/Libs/Redux');
var ApolloClient = require('build/Libs/ApolloClient');
var createNetworkInterface = require('build/Libs/createNetworkInterface');
var gql = require('fusejs_lib/graphql-tag_graphql-tag.umd');
This way still could use some TLC but for now, it works and get's the job done:
var networkInterface = createNetworkInterface.createNetworkInterface({
uri: 'http://localhost:8000/graphql',
});
var client = new ApolloClient.ApolloClient({
networkInterface,
});
client.query({
query: gql`
query {
allPosts {
edges {
node {
id
headline
summary(length: 80)
body
createdAt
updatedAt
personByAuthorId {
firstName
lastName
}
}
}
}
}
`,
})
.then(data => data.data.allPosts.edges.forEach(node => pages.add(createPage(node))))
.catch(error => console.log(error));
Also if you like I've setup a whole project along with server that might be of an interest to you: fuseR
I made fusepm, which has a mode to convert npm modules to run them under FuseTools. It's still has a lot of bugs, but at least I managed to come longer than you:
fuse create app apolloc
cd apolloc
npm install apollo-client
fusepm npm apollo-client
And then in your javascript:
<JavaScript>
var ApolloClient = require('fusejs_lib/apollo-client.js');
</JavaScript>
fusepm uses Babel, with some custom plugins.

node.js call some methods using OOP way

I need to call some methods using OOP way e.g. this.method() but i get some errors, this my BingoCard.js help please.
var _ = require('underscore');
// ------------------------------------ ---------
// Constructor
// ---------------------------------------------
function BingoCard() {
if(false === (this instanceof BingoCard)) {
return new BingoCard();
}
this.firstRowSchema = [];
this.secondRowSchema = [];
this.thirdRowSchema = [];
this.firstRow = [];
this.secondRow = [];
this.thirdRow = [];
this.patterns = [
{
"1" : ['x','0','x','0','x','0','x','x','0'],
"2" : ['0','x','0','x','0','x','0','x','x'],
"3" : ['x','0','x','0','x','0','x','0','x']
},
{
"1" : ['x','x','0','x','0','x','0','x','0'],
"2" : ['0','x','x','0','x','0','x','0','x'],
"3" : ['x','0','x','x','0','x','0','x','0']
}
];
this.columns = {
"1": [1,2,3,4,5,6,7,8,9],
"2": [10,11,12,13,14,15,16,17,18,19],
"3": [20,21,22,23,24,25,26,27,28,29],
"4": [30,31,32,33,34,35,36,37,38,39],
"5": [40,41,42,43,44,45,46,47,48,49],
"6": [50,51,52,53,54,55,56,57,58,59],
"7": [60,61,62,63,64,65,66,67,68,69],
"8": [70,71,72,73,74,75,76,77,78,79],
"9": [80,81,82,83,84,85,86,87,88,89,90]
};
// Use Underscore to bind all of our methods
// to the proper context
_.bindAll(this);
}
// ---------------------------------------------
// Methods
// ---------------------------------------------
BingoCard.prototype = {
resetSchemas: function () {
this.firstRowSchema = [];
this.secondRowSchema = [];
this.thirdRowSchema = [];
},
generateRows: function () {
this.cardID = _.random(8888, 999999999); // generate a Card ID.
var pattern = _.shuffle(this.patterns);
this.firstRow = pattern[0][1];
this.secondRow = pattern[0][2];
this.thirdRow = pattern[0][3];
},
createColNumber: function (col,equalNumbers) {
console.log(this.patterns);
var colNumber = this.getColNumber(col);
if(typeof equalNumbers !== 'undefined' && equalNumbers.length > 0){
equalNumbers.forEach(function(val,key){
while(colNumber == val){
colNumber = this.getColNumber(col);
}
});
}
return colNumber;
},
getColNumber: function () {
var items = _.shuffle(this.columns[col]);
return items[0];
},
generateFirstRow: function () {
var col = 0;
this.firstRow.forEach(function(val,key){
col++;
if(val == 'x'){
this.firstRowSchema[key] = this.createColNumber(col);
} else {
this.firstRowSchema[key] = 0;
}
});
return this.firstRowSchema;
}
};
// ---------------------------------------------
// Export
// ---------------------------------------------
module.exports = BingoCard;
I call the bingocard class in app.js and this is my app.js contents.
var BingoCard = require('./bingocard');
var bingocard = new BingoCard();
bingocard.generateRows();
console.log(bingocard.generateFirstRow());
When in run "node app" from console i get this error:
TypeError: Object #<Object> has no method 'createColNumber'
at /var/www/bingo/bingocard.js:10:48
but createColNumber method defined .. :(?
On the fourth row in the code below, this is not referring to the prototype. this is pointing to something else.
this.firstRow.forEach(function(val,key){
col++;
if(val == 'x'){
this.firstRowSchema[key] = this.createColNumber(col);
} else {
this.firstRowSchema[key] = 0;
}
});
You can solve this by switching out this with self. and assign this to self in the beginning of the method definition. Like this:
generateFirstRow: function () {
var col = 0,
self = this;
this.firstRow.forEach(function(val,key){
col++;
if(val == 'x'){
self.firstRowSchema[key] = self.createColNumber(col);
} else {
self.firstRowSchema[key] = 0;
}
});
return this.firstRowSchema;
}

Knockout-2.2.0, subscribe get value before change AND new value

jsfiddle link: http://jsfiddle.net/T8ee7/
When I call Knockout's subscribe method is there a way I can get both the previous and new value? Right now, I can only call get these values separately.
I want to trigger some code if the old and new value are different.
I suppose I could do the following, but it can get messy...
(http://jsfiddle.net/MV3fN/)
var sv = sv || {};
sv.PagedRequest = function (pageNumber, pageSize) {
this.pageNumber = ko.observable(pageNumber || 1);
this.numberOfPages = ko.observable(1);
this.pageSize = ko.observable(pageSize || sv.DefaultPageSize);
};
var _pagedRequest = new sv.PagedRequest();
var oldValue;
_pagedRequest.pageNumber.subscribe(function (previousValue) {
console.log("old: " + previousValue);
oldValue = previousValue;
}, _pagedRequest, "beforeChange");
_pagedRequest.pageNumber.subscribe(function (newValue) {
console.log("new: " + newValue);
if (oldValue != newValue) {
console.log("value changed!");
}
});
_pagedRequest.pageNumber(10);
_pagedRequest.pageNumber(20);
​
I prefer using an observable extender.
http://jsfiddle.net/neonms92/xybGG/
Extender:
ko.extenders.withPrevious = function (target) {
// Define new properties for previous value and whether it's changed
target.previous = ko.observable();
target.changed = ko.computed(function () { return target() !== target.previous(); });
// Subscribe to observable to update previous, before change.
target.subscribe(function (v) {
target.previous(v);
}, null, 'beforeChange');
// Return modified observable
return target;
}
Example Usage:
// Define observable using 'withPrevious' extension
self.hours = ko.observable().extend({ withPrevious: 1 });
// Subscribe to observable like normal
self.hours.subscribe(function () {
if (!self.hours.changed()) return; // Cancel if value hasn't changed
print('Hours changed from ' + self.hours.previous() + ' to ' + self.hours());
});
This seems to work for me
ko.observable.fn.beforeAndAfterSubscribe = function (callback, target) {
var _oldValue;
this.subscribe(function (oldValue) {
_oldValue = oldValue;
}, null, 'beforeChange');
this.subscribe(function (newValue) {
callback.call(target, _oldValue, newValue);
});
};
See more at: http://ideone.com/NPpNcB#sthash.wJn57567.dpuf
http://jsfiddle.net/MV3fN/3/
var sv = sv || {};
sv.PagedRequest = function (pageNumber, pageSize) {
var self = this;
self.pageNumber = ko.observable(pageNumber || 1);
self.numberOfPages = ko.observable(1);
self.pageSize = ko.observable(pageSize || sv.DefaultPageSize);
self.pageNumber.subscribe(function (previousValue) {
console.log(previousValue);
console.log(self.pageNumber.arguments[0]);
if (previousValue != _pagedRequest.pageNumber.arguments[0]) {
console.log('value changed');
}
else {
//This won't get executed because KO doesn't
//call the function if the value doesn't change
console.log('not changed');
}
}, _pagedRequest, "beforeChange");
};
var _pagedRequest = new sv.PagedRequest();
_pagedRequest.pageNumber(10);
_pagedRequest.pageNumber(20);
_pagedRequest.pageNumber(20);
_pagedRequest.pageNumber(5);
I don't know if you're really supposed to use arguments[0], but it seems to work.
You could also set up your own method to accomplish this in a much cleaner way:
http://jsfiddle.net/PXKgr/2/
...
self.setPageNumber = function(page) {
console.log(self.pageNumber());
console.log(page);
if (self.pageNumber() != page) {
console.log('value changed');
}
else {
console.log('not changed');
}
self.pageNumber(page);
};
...
_pagedRequest.setPageNumber(10);
_pagedRequest.setPageNumber(20);
_pagedRequest.setPageNumber(20);
_pagedRequest.setPageNumber(5);

Resources