Working with a POC using Bacon.js and run into a little bit of an issue with Property values.
I am able to retrieve all new property values in the onValue callback however I would like to know what the old property value was before this new value has been set. So far I have not found any easy or elegant solution to achieve this in Bacon out of the box...am I missing something.
Even Object.observe() has a way to get to the old value of the property so surprised I cannot find equivalent behaviour in Bacon.
Would anyone have any suggestions how to handle this? Obviously I do not want to persist the latest property value anywhere in the client code strcily for the sake of being able to do the comparisons between old and new...
You could use slidingwindow to create a new observable with the 2 latest values:
var myProperty = Bacon.sequentially(10, [1,2,3,4,5]) // replace with real property
var slidingWindow = myProperty.startWith(null).slidingWindow(2,2)
slidingWindow.onValues(function(oldValue, newValue) {
// do something with the values
})
Due to lack of the functionality in the native Bacon.js I implemented a custom solution with a wrapper object that holds on to the latest value after it had been forwarded to the subscriber. So instead of tapping into the lens directly client code works with the obsever which also has additional benefits of restricting write access to the model through the lens from client code which is what I needed as well.
function Observer (lens) {
this.lastValue = undefined;
this.lens = lens;
};
Observer.prototype = {
onValue(onValueCallback){
this.subscription = this.lens.onValue(function(newValue) {
onValueCallback(this.lastValue, newValue);
this.lastValue = newValue;
});
},
};
var model = new Bacon.Model({ type : "A"});
var observer = new Observer(model.lens());
observer.onValue(function(oldValue,newValue) { ... });
Related
The question is related to general js programming, but I'll use nightwatch.js as an example to elaborate my query.
NightWatch JS provides various chaining methods for its browser components, like: -
browser
.setValue('input[name='email']','example#mail.com')
.setValue('input[name='password']', '123456')
.click('#submitButton')
But if I'm writing method to select an option from dropdown, it requires multiple steps, and if there are multiple dropdowns in a form, it gets really confusing, like: -
browser
.click(`#country`)
.waitForElementVisible(`#india`)
.click(`#india`)
.click(`#state`)
.waitForElementVisible(`#delhi`)
.click(`#delhi`)
Is it possible to create a custom chaining method to group these already defined methods? For example something like:
/* custom method */
const dropdownSelector = (id, value) {
return this
.click(`${id}`).
.waitForElementVisible(`${value}`)
.click(`${value}`)
}
/* So it can be used as a chaining method */
browser
.dropdownSelector('country', 'india')
.dropdownSelector('state', 'delhi')
Or is there any other way I can solve my problem of increasing reusability and readability of my code?
I'm somewhat new to JS so couldn't tell you an ideal code solution, would have to admit I don't know what a proxy is in this context. But in the world of Nightwatch and test-automation i'd normally wrap multiple steps I plan on reusing into a page object. Create a new file in a pageObject folder and fill it with the method you want to reuse
So your test...
browser
.click(`#country`)
.waitForElementVisible(`#india`)
.click(`#india`)
.click(`#state`)
.waitForElementVisible(`#delhi`)
.click(`#delhi`)
becomes a page object method in another file called 'myObject' like...
selectLocation(browser, country, state, city) {
browser
.click(`#country`) <== assume this never changes?
.waitForElementVisible(country)
.click(country)
.click(state)
.waitForElementVisible(city)
.click(city);
}
and then each of your tests inherit the method and define those values themselves, however you chose to manage that...
const myObject = require ('<path to the new pageObject file>')
module.exports = {
'someTest': function (browser) {
const country = 'something'
const state = 'something'
const city = 'something'
myObject.selectLocation(browser);
You can also set your country / state / city as variables in a globals file and set them as same for everything but I don't know how granular you want to be.
Hope that made some sense :)
This is a great place to use a Proxy. Given some class:
function Apple ()
{
this.eat = function ()
{
console.log("I was eaten!");
return this;
}
this.nomnom = function ()
{
console.log("Nom nom!");
return this;
}
}
And a set of "extension methods":
const appleExtensions =
{
eatAndNomnom ()
{
this.eat().nomnom();
return this;
}
}
We can create function which returns a Proxy to select which properties are retrieved from the extension object and which are retrieved from the originating object:
function makeExtendedTarget(target, extensions)
{
return new Proxy(target,
{
get (obj, prop)
{
if (prop in extensions)
{
return extensions[prop];
}
return obj[prop];
}
});
}
And we can use it like so:
let apple = makeExtendedTarget(new Apple(), appleExtensions);
apple
.eatAndNomnom()
.eat();
// => "I was eaten!"
// "Nom nom!"
// "I was eaten!"
Of course, this requires you to call makeExtendedTarget whenever you want to create a new Apple. However, I would consider this a plus, as it makes it abundantly clear you are created an extended object, and to expect to be able to call methods not normally available on the class API.
Of course, whether or not you should be doing this is an entirely different discussion!
Hopefully this question won't be flagged as too subjective but I'm newish to OOP and struggling a bit when it come to sharing data between parts of my code that I think should be separated to some extent.
I'm building a (non-geo) map thing (using leaflet.js which is superduper) which has a map (duh) and a sidebar that basically contains a UI (toggling markers both individually and en masse, searching said marker toggles as well as other standard UI behaviour). Slightly confused about organisation too (how modular is too modular but I can stumble through that myself I guess). I am using a simple JSON file for my settings for the time being.
I started with static methods stored in objects which is essentially unusable or rather un-reusable so I went for nested constructors (kinda) so I could pass the parent scope around for easier access to my settings and states properties:
function MainThing(settings) {
this.settings = options;
this.states = {};
}
function SubthingMaker(parent) {
this.parent = parent;
}
SubthingMaker.prototype.method = function() {
var data = this.parent.settings.optionOne;
console.log(data);
this.parent.states.isVisible = true;
};
MainThing.prototype.init = function() {
this.subthing = new SubthingMaker(this);
// and some other fun stuff
};
And then I could just create and instance of MainThing and run MainThing.init() and it should all work lovely. Like so:
var options = {
"optionOne": "Hello",
"optionTwo": "Goodbye"
}
var test = new MainThing(options);
test.init();
test.subthing.method();
Should I really be nesting in this manner or will it cause me problems in some way? If this is indeed okay, should I keep going deeper if needed (maybe the search part of my ui wants its own section, maybe the map controls should be separate from DOM manipulation, I dunno) or should I stay at this depth? Should I just have separate constructors and store them in an object when I create an instance of them? Will that make it difficult to share/reference data stored elsewhere?
As regards my data storage, is this an okay way to handle it or should I be creating a controller for my data and sending requests and submissions to it when necessary, even if that data is then tucked away in simple JSON format? this.parent does really start to get annoying after a while, I suppose I should really be binding if I want to change my scope but it just doesn't seem to be an elegant way to access the overall state data of the application especially since the UI needs to check the state for almost everything it does.
Hope you can help and I hope I don't come across as a complete idiot, thanks!
P.S. I think the code I posted works but if it doesn't, its the general idea I was hoping to capture not this specific example. I created a much simpler version of my actual code because I don't want incur the wrath of the SO gods with my first post. (Yes, I did just use a postscript.)
An object may contain as many other objects as are appropriate for doing it's job. For example, an object may contain an Array as part of its instance data. Or, it may contain some other custom object. This is normal and common.
You can create/initialize these other objects that are part of your instance data in either your constructor or in some other method such as a .init() method whichever is more appropriate for your usage and design.
For example, you might have a Queue object:
function Queue() {
this.q = [];
}
Queue.prototype.add = function(item) {
this.q.push(item);
return this;
}
Queue.prototype.next = function() {
return this.q.shift();
}
var q = new Queue();
q.add(1);
q.add(2);
console.log(q.next()); // 1
This creates an Array object as part of its constructor and then uses that Array object in the performance of its function. There is no difference here whether this creates a built-in Array object or it calls new on some custom constructor. It's just another Javascript object that is being used by the host object to perform its function. This is normal and common.
One note is that what you are doing with your MainThing and SubthingMaker violates OOP principles, because they are too tightly coupled and have too wide access to each other internals:
SubthingMaker.prototype.method = function() {
// it reads something from parent's settings
var data = this.parent.settings.optionOne;
console.log(data);
// it changes parent state directly
this.parent.states.isVisible = true;
};
While better idea could be to make them less dependent.
It is probably OK for the MainThing to have several "subthings" as your main thing looks like a top-level object which will coordinate smaller things.
But it would be better to isolate these smaller things, ideally they should work even there is no MainThing or if you have some different main thing:
function SubthingMaker(options) {
// no 'parent' here, it just receives own options
this.options = options;
}
SubthingMaker.prototype.method = function() {
// use own options, instead of reading then through the MainThing
var data = this.options.optionOne;
console.log(data);
// return the data from the method instead of
// directly modifying something in MainThing
return true;
this.parent.states.isVisible = true;
};
MainThing.prototype.doSomething = function() {
// MainThing calls the subthing and modifies own data
this.parent.states.isVisible = this.subthing.method();
// and some other fun stuff
};
Also to avoid confusion, it is better not to use parent / child terms in this case. What you have here is aggregation or composition of objects, while parent / child are usually used to describe the inheritance.
I'm trying to learn object-oriented javascript. Working with a simple method I want to do this:
var users = function(url){
this.url = url;
this.log = function(){
console.log(this.url);
}
}
var apiPoint = "https://www.zenconomy.se/api/admin/tracking?format=json"
var liveUsers = new users(apiPoint)
liveUsers.log()
However, I've learned that it's often a good idea to pass variables into functions when working with normal functions, in objects however, this seems a bit clunky.
var users = function(url){
this.url = url;
this.log = function(url){
console.log(url);
}
}
var apiPoint = "here is my url"
var liveUsers = new users(apiPoint)
liveUsers.log(liveUsers.url)
Both methods work. What are the pros and cons of the different approaches, assuming that users.log only ever need properties from inside the users-class.
you just mentioned you are trying to learn OOP in javascript, but actually, consider the log function in your user object, if there is no users instance, no log method eigther. That's not the same concept according to OO in C++ or C#. In my opinion, prototype will best describe the oop, do as following:
var users = function(url){
this.url = url;
}
users.prototype.log = function(){
console.log(this.url);
}
in this way, log will not be in any instance of users, it exists in __proto__ which is a reference of prototype in any instance. That means when you create instances, they share all the functions, same as C++ or C#. finally, you should never use the second sample in your post, that's not OO things.
If you want log to always print the object's URL, then of course you would not pass in the object's URL as a parameter, since log can get it itself.
If you want to log various properties of the object, I'd suggest making separate routines such as logUrl and logBlah for the individual cases.
If you want log to print some arbitrary value, then it goes without saying that you need to pass in the value.
If there is nothing about logging that relates to the object, then you can just have a logging routine independent of the object that logs whatever you pass it.
Please note that Object.Watch and Object.Observe are both deprecated now (as of Jun 2018).
I was looking for an easy way to monitor an object or variable for changes, and I found Object.watch(), that's supported in Mozilla browsers, but not IE. So I started searching around to see if anyone had written some sort of equivalent.
About the only thing I've found has been a jQuery plugin, but I'm not sure if that's the best way to go. I certainly use jQuery in most of my projects, so I'm not worried about the jQuery aspect...
Anyway, the question: Can someone show me a working example of that jQuery plugin? I'm having problems making it work...
Or, does anyone know of any better alternatives that would work cross browser?
Update after answers:
Thanks everyone for the responses! I tried out the code posted here:
http://webreflection.blogspot.com/2009/01/internet-explorer-object-watch.html
But I couldn't seem to make it work with IE. The code below works fine in Firefox, but does nothing in IE. In Firefox, each time watcher.status is changed, the document.write() in watcher.watch() is called and you can see the output on the page. In IE, that doesn't happen, but I can see that watcher.status is updating the value, because the last document.write() call shows the correct value (in both IE and FF). But, if the callback function isn't called, then that's kind of pointless... :)
Am I missing something?
var options = {'status': 'no status'},
watcher = createWatcher(options);
watcher.watch("status", function(prop, oldValue, newValue) {
document.write("old: " + oldValue + ", new: " + newValue + "<br>");
return newValue;
});
watcher.status = 'asdf';
watcher.status = '1234';
document.write(watcher.status + "<br>");
(Sorry for the cross-posting, but this answer I gave to a similar question works fine here)
I have created a small object.watch shim for this a while ago. It works in IE8, Safari, Chrome, Firefox, Opera, etc.
That plugin simply uses a timer/interval to repeatedly check for changes on an object. Maybe good enough but personally I would like more immediacy as an observer.
Here's an attempt at bringing watch/unwatch to IE: http://webreflection.blogspot.com/2009/01/internet-explorer-object-watch.html.
It does change the syntax from the Firefox way of adding observers. Instead of :
var obj = {foo:'bar'};
obj.watch('foo', fooChanged);
You do:
var obj = {foo:'bar'};
var watcher = createWatcher(obj);
watcher.watch('foo', fooChanged);
Not as sweet, but as an observer you are notified immediately.
The answers to this question are a bit outdated. Object.watch and Object.observe are both deprecated and should not be used.
Today, you can now use the Proxy object to monitor (and intercept) changes made to an object. Here's a basic example:
var targetObj = {};
var targetProxy = new Proxy(targetObj, {
set: function (target, key, value) {
console.log(`${key} set to ${value}`);
target[key] = value;
}
});
targetProxy.hello_world = "test"; // console: 'hello_world set to test'
If you need to observe changes made to a nested object, then you need to use a specialized library. I published Observable Slim and it works like this:
var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
console.log(JSON.stringify(changes));
});
p.testing.blah = 42; // console: [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]
Current Answer
Use the new Proxy object, which can watch changes to it's target.
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// The default behavior to store the value
obj[prop] = value;
// Indicate success
return true;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Throws an exception
person.age = 300; // Throws an exception
Old answer from 2015
You could have used Object.observe() from ES7. Here's a polyfill. But Object.observe() is now cancelled. Sorry people!
Note that in Chrome 36 and higher you can use Object.observe as well. This is actually a part of a future ECMAScript standard, and not a browser-specific feature like Mozilla's Object.watch.
Object.observe only works on object properties, but is a lot more performant than Object.watch (which is meant for debugging purposes, not production use).
var options = {};
Object.observe(options, function(changes) {
console.log(changes);
});
options.foo = 'bar';
you can use Object.defineProperty.
watch the property bar in foo
Object.defineProperty(foo, "bar", {
get: function (val){
//some code to watch the getter function
},
set: function (val) {
//some code to watch the setter function
}
})
I have used Watch.js in one of my projects. And it is working fine.One of the main advantage of using this library is :
"With Watch.JS you will not have to change the way you develop."
The example is given below
//defining our object however we like
var ex1 = {
attr1: "initial value of attr1",
attr2: "initial value of attr2"
};
//defining a 'watcher' for an attribute
watch(ex1, "attr1", function(){
alert("attr1 changed!");
});
//when changing the attribute its watcher will be invoked
ex1.attr1 = "other value";
<script src="https://cdn.jsdelivr.net/npm/melanke-watchjs#1.5.0/src/watch.min.js"></script>
This is as simple as this!
This works for me
$('#img').hide().attr('src', "path/newImage.jpg").fadeIn('slow');
I also think that right now the best solution is to use Watch.JS, find a nice tutorial here: Listen/Watch for object or array changes in Javascript (Property changed event on Javascript objects)
I'm currently facing a conundrum: What is the right way to wire together 2 javascript objects?
Imagine an application like a text editor with several different files. I have some HTML page that represents the view for the notebook. I have a file notebook.js that contains class definitions for NotebookController and Notebook View.
NotebookControler object responsible for performing business logic on the Notebook like "Save Notebook," "Load Notebook," "New Notebook." NotebookView is responsible for managing the HTML that is used for presentation. It does low level stuff like "get/set notebook body" "get/set notebook name." It also listens for DOM events (onClick) and fires business events (saveNotebook). This is my attempt at the Passive View pattern.
I want my javascript client-side code to be object-oriented, separated concerns, and unit-testable. I want to test NotebookController with a mock NotebookView and vice versa. This means that I can't just instantiate a NotebookView inside the NotebookController. So do I
Put some logic in my notebook.js that wires the 2 together
Have a global function in my application that knows to instantiate one of each and wire them together
Use Dependency Injection, either a home-grown one or something like SquirrelIoc
In Java, the choice is a natural one: use Spring. But that doesn't seem very JavaScript-y. What's the right thing to do?
Dependency injection is probably your best bet. Compared to Java, some aspects of this are easier to do in JS code, since you can pass an object full of callbacks into your NotebookController. Other aspects are harder, because you don't have the static code analysis to formalize the interface between them.
Thanks for the insight. I ended up writing a simple JavaScript dependency injection utility. After debating for a while and your comments, it occured to me that DI was really the right answer because:
It totally separated the concerns of wiring from the business logic while keeping the wiring logic close to the things being wired.
It allowed me to generically provide a "you're all wired up" callback on my objects so that I could do a 3 phase initialization: instantiate everything, wire it all up, call everyone's callbacks and tell them they're wired.
It was easy to check for dependency missing problems.
So here's the DI utility:
var Dependency = function(_name, _instance, _dependencyMap) {
this.name = _name;
this.instance = _instance;
this.dependencyMap = _dependencyMap;
}
Dependency.prototype.toString = function() {
return this.name;
}
CONCORD.dependencyinjection = {};
CONCORD.dependencyinjection.Context = function() {
this.registry = {};
}
CONCORD.dependencyinjection.Context.prototype = {
register : function(name, instance, dependencyMap) {
this.registry[name] = new Dependency(name, instance, dependencyMap);
},
get : function(name) {
var dependency = this.registry[name];
return dependency != null ? dependency.instance : null;
},
init : function() {
YAHOO.log("Initializing Dependency Injection","info","CONCORD.dependencyinjection.Context");
var registryKey;
var dependencyKey;
var dependency;
var afterDependenciesSet = [];
for (registryKey in this.registry) {
dependency = this.registry[registryKey];
YAHOO.log("Initializing " + dependency.name,"debug","CONCORD.dependencyinjection.Context");
for(dependencyKey in dependency.dependencyMap) {
var name = dependency.dependencyMap[dependencyKey];
var instance = this.get(name);
if(instance == null) {
throw "Unsatisfied Dependency: "+dependency+"."+dependencyKey+" could not find instance for "+name;
}
dependency.instance[dependencyKey] = instance;
}
if(typeof dependency.instance['afterDependenciesSet'] != 'undefined') {
afterDependenciesSet.push(dependency);
}
}
var i;
for(i = 0; i < afterDependenciesSet.length; i++) {
afterDependenciesSet[i].instance.afterDependenciesSet();
}
}
}
I would say, just wire them together:
function wireTogether() {
var v = new View();
var c = new Controller();
c.setView(v);
}
But then of course another question raises - how do you test the wireTogether() function?
Luckily, JavaScript is a really dynamic language, so you can just assign new values to View and Controller:
var ok = false;
View.prototype.isOurMock = true;
Controller.prototype.setView = function(v) {
ok = v.isOurMock;
}
wireTogether();
alert( ok ? "Test passed" : "Test failed" );
There is also a framework for dependency injection for JavaScript: https://github.com/briancavalier/wire
I have a inversion of control library for javascript, I'm pretty happy with it. https://github.com/fschwiet/jsfioc. It also supports events, so if you want to have a startup event thats fine. It could use more documentation...
http://github.com/fschwiet/jsfioc
Another (newer?) option, which has better documentation and support, is requireJS (http://requirejs.org/).
I'll try to take a stab at this, but it will be a little difficult without seeing any actual code. Personally, I've never seen anybody do such a specific attempt at (M)VC with JavaScript or IoC for that matter.
First of all, what are you going to test with? If you haven't already, check out the YUI Test video which has some good info on unit testing with javascript.
Secondly, when you say "the best way to wire up that aggregation" I would probably just do it as a setter w/the controller
// Production
var cont = new NotebookController();
cont.setView( new NotebookView() );
// Testing the View
var cont = new NotebookController();
cont.setView( new MockNotebookView() );
// Testing the Controller
var cont = new MockNotebookController();
cont.setView( new NotebookView() );
// Testing both
var cont = new MockNotebookController();
cont.setView( new MockNotebookView() );
But this makes some big assumption on how you've designed your controller and view objects already.