Using the new symbol type in ES6 you can set non-iterable properties on objects. However when using Knockout these symbols are not observed by default.
It is possible to bind a symbol's value, but it is never updated as it isn't added to the observable object.
Has anyone been able to work around this problem and force Knockout to observe symbols?
Looks like the observable plugin for Durandal is implemented similarly to the Knockout-ES5 plugin. When applied to a view model it's only going to create observables wrapped in a getter/setter for properties that are enumerable on the object.
observable.defineProperty doesn't accept enumerable as a param but it does have configuration: true. This means that we can use observable.defineProperty (which will make the property enumerable) but then immediately make the property non-enumerable like so...
Object.defineProperty(this, 'myProp', { enumerable: false });
Related
In KnockoutJS, we can go
ko.mapping.toJS(object)
and get our object returned with observables and whatnot converted to vanilla Javascript object. Now, ko.mapping.toJS ignores computed properties. I have a scenario where I basically would like the functionality of ko.mapping.toJS to retain my pureComputed fields with whatever value they had at the time.
I've looked into the documentations page, but it looks like the "mapping options" are for the fromJS method, not toJS.
Any way I can convert my Knockout Object to a JS object but retain the pureComputeds being regular properties in the output?
I switched from ko.mapping.toJS to ko.toJS and the output of ko.toJS does include the computed properties like I want, so that seems to be all I need.
I am reading about getters and setters in javascript. I would like to know if there is a difference between this two ways of coding with and without setters
first way, without setters.
>obj1 = {
arr: [];
}
>obj1.arr.push('first')
>obj1.arr
[ 'first' ]
Second way, with setters.
>obj2 = {
set add(data) {
this.arr.push(data);
},
arr: []
}
>obj2.add = 'first'
>obj2.arr
[ 'first' ]
The setter syntax in your example does not really prevent the client code to still add a value using the direct push call as in the first code block. So the difference is that you just added another way to do the same thing.
To make a fair comparison, you would have to define the same method in both alternatives: once as a normal method and once as a setter method, and then the difference is just the syntax how the argument is passed to the method, either with obj.add('first') or obj.add = 'first'.
In this actual case I would vote against the setter, because it gives the false impression that if you "assign" another value, the first assigned value is overwritten:
obj.add = 'first';
obj.add = 'second';
... but obviously this is not the case: both values exist in the object now.
First, The set Syntax bind an object property to a defined function. In this particular example, there is no difference between two codes, but let's say for example you want to check if the value is negative before adding it to the array, so you can use set to Encapsulate that behavior.
So basically, using setter is only to add additional encapsulated behavior to the functions of the objects.
The way of accessing the array index called bracket notation. it is equal to dot notation, except the bracket notation allows you to set new properties to objects or arrays dynamically.
Hope this help you.
I think difference only about "how it looks like". Using setters it's closest way for understanding for people who came to js from object oriented languages.
The getter/setter property is not the same as "normal" instance property, one is called "named data property", the other is called "named accessor property".
Please let met quote below part of documents from the ECMAScript 5.1.
https://www.ecma-international.org/ecma-262/5.1/#sec-8.10.1
An Object is a collection of properties. Each property is either a
named data property, a named accessor property, or an internal
property:
A named data property associates a name with an ECMAScript language
value and a set of Boolean attributes.
A named accessor property associates a name with one or two accessor
functions, and a set of Boolean attributes. The accessor functions are
used to store or retrieve an ECMAScript language value that is
associated with the property.
An internal property has no name and is not directly accessible via
ECMAScript language operators. Internal properties exist purely for
specification purposes.
There are two kinds of access for named (non-internal) properties: get
and put, corresponding to retrieval and assignment, respectively.
And
If the value of an attribute is not explicitly specified by this
specification for a named property, the default value defined in Table
7 is used.
So I have this computed property inside my component.js: contexts: Ember.computed.oneWay('myService.contexts'),
And I am able to get the content from another action
openHelp(){
console.log(this.get('contexts'))
alert(this.get('contexts'))
}
}
But when I try to use the computed property in Handlebars ({{contexts}}) it's just blank.
I created an Ember Twiddle for this question: https://ember-twiddle.com/38de64d58dcf3298df6d4176f15cbc0e?openFiles=components.my-component-help.js%2Ctemplates.components.my-component-help.hbs
If I have an array foo: [ 'foo','bar'] and I do {{foo}} it outputs in handlebars. But if I make foo a computed property that gets [ 'foo','bar'] from and do {{foo}} I get nothing.
Here's the solution: https://ember-twiddle.com/e9c2ef05e27013a389e0b2bfdaec3d40?openFiles=services.my-service.js%2Ctemplates.components.my-component-help.hbs
There were two issues:
contexts is an array. When you console.log or alert it, those methods internally in some browsers JSON.stringify the object for you for your convenience. Ember will not do that. You need to format the array yourself or, as I did, each over it. For debugging purposes, feel free to use the log helper.
Computed properties on arrays are watching for array mutations through Ember's methods such as pushObject and removeObject. Simply using push or splice won't update the computed property.
Can't comment on the above answer which is correct because I don't have enough reputation, but I wanted to add a link to the documentation relating to Ember's observable methods for enumerables:
https://guides.emberjs.com/v2.5.0/object-model/enumerables/
What is the difference between assigning a property to an object and defining it?Which one is better and how?
This
Object.defineProperty(obj,p,propDesc)
Or simply
obj.p="someValue";
Object.defineProperty lets you set a whole bunch of options about that property. Like enumerable and writable.
When you do obj.p = 'something';, you're setting a property with the "default" options.
Neither is "better", they each have their own uses. Which one you use depends on your requirements.
As found on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
"
This method allows precise addition to or modification of a property on an object. Normal property addition through assignment creates properties which show up during property enumeration (for...in loop or Object.keys method), whose values may be changed, and which may be deleted. This method allows these extra details to be changed from their defaults."
I am a beginner in Knockout and I must say I often get confused regarding when to use (). Is there any general tip/trick regarding when would you use () against when you would not because at the moment I am just doing trial and error. If the binding throws error or doesn't update values I remove () else I put.
I feel like the existing answers skip over a very important point of confusion: data-bind attributes.
It is true that you use the parens when you are in Javascript, and getting or setting observables. But when you are writing data-bind="text: property", you leave out the parens even when working with observables.
Edit
As noted in the comment below, bindings that are expressions, or access properties of observbles, require parens
visible: personName().length > 0
visible: person().Name().length > 0
visible: person().isVisible
Note that the last one person and isVisisble are both observables, but the last property doesn't use parens! The reason for this is that we would be passing a value to the binding instead of an observable, and it wouldn't update.
You use () in knockout when using observables or when executing any other method.
Knockout observables are functions, invoked to return you what you looking for or allow you to assign new values.
In knockout you use object.property() to retrieve a value and object.property(newValue) to assign a value to that property.
On the knockout website checkout the documentation, specifically the section on observables, which shows you the use of the () when querying and writing observables.
To quote:
var myViewModel = {
personName: ko.observable('Bob'),
personAge: ko.observable(123)
};
To read the observable’s current value, just call the observable with no parameters. In this example, myViewModel.personName() will
return 'Bob', and myViewModel.personAge() will return 123.
To write a new value to the observable, call the observable and pass the new value as a parameter. For example, calling
myViewModel.personName('Mary') will change the name value to 'Mary'.
To write values to multiple observable properties on a model object, you can use chaining syntax. For example,
myViewModel.personName('Mary').personAge(50) will change the name
value to 'Mary' and the age value to 50.
Knockout's interactive tutorial is also quite nice and well worth going through.
Basically whenever you're working with an observable value (array or otherwise) you should use the parentheses to get the value and set the value.
var something = ko.obserbable();
something(5); //set value
console.log(something()); //get value: 5
The reason being that most JS implementations do not support getters and setters for properties yet, so observables were implemented like this to get around this limitation.