What is the difference between WinJS.Binding.mixin and WinJS.Binding.dynamicObservableMixin? - windows-8

In WinJS there are three binding related mixins:
WinJS.Binding.observableMixin
WinJS.Binding.dynamicObservableMixin
WinJS.Binding.mixin
Both WinJS.Binding.mixin and WinJS.Binding.dynamicObservableMixin define the same methods to mix. The only difference between their definition is that WinJS.Binding.mixin is defined as a non enumerable property on the WinJS.Binding namespace, while WinJS.Binding.dynamicObservableMixin is defined as an enumerable property:
WinJS.Namespace.define("WinJS.Binding", {
mixin: { value: dynamicObservableMixin, enumerable: false, writable: true, configurable: true },
dynamicObservableMixin: { value: dynamicObservableMixin, enumerable: true, writable: true, configurable: true },
});
I don't see any real difference between these two mixins - I don't see the relevance of the difference of the enumerable flag on this property. Is there any semantic or other difference as to which mixin of the two one is using?

You are right. There is no real difference between mixin and dynamicObservableMixin. They are same.
WinJS.Binding.mixin adds methods like addProperty, removeProperty, get/setProperty which are used by WinJS.Binding.expandProperties. expandProperties is used to make an existing class observable. dynamic nature is attributed to dynamically adding properties to an object.
Example:
var MyListViewModel = WinJS.Class.define(
function MyListViewModel_ctor()
{
this._initObservable();
},
{
load: function load()
{
var self = this;
return serviceclient.getMyListData().then(function (records)
{
self.items = new WinJS.Binding.List(records);
});
}
});
WinJS.Class.mix(MyListViewModel,
WinJS.Binding.mixin,
WinJS.Binding.expandProperties({ items: '' }));
There is difference between observableMixin and mixin. observableMixin only has bind, unbind and notify methods.

Related

Will computed property be dependent on a data property if I use data property only for checking if it is defined?

I have this vue component:
export default {
data: function() {
return {
editor: new Editor({
//some options
}),
}
},
computed: {
doc(){ // <--------------------- take attention on this computed property
return this.editor ? this.editor.view.state.doc : null;
},
},
watch: {
doc: {
handler: function(val, OldVal){
// call some this.editor methods
},
deep: true,
immediate: true,
},
},
}
Will computed property doc be dependent on a data property editor if I use this.editor only for checking if it is defined and not use it for assigning it to the doc? I mean, If I will change this.editor will doc be changed? Also, I have watcher on doc so I need to know if I will cause an infinite loop.
In the doc property computation, you use:
the editor property (at the beginning of your ternary, this.editor ? ...)
if editor exists, the editor.view.state.doc property
So the computation of doc will be registered by Vue reactivity system as an effect related to the properties editor and (provided that editor exists) to editor.view.state.doc. In other words, the doc property will be reevaluated each time one of these two properties changes.
=> to reply to the initial question, doc will indeed depend on editor.
This can be toned though, because by 'property change', we mean:
for properties of primitive types, being reassigned with a different value
for objects, having a new reference
So, in our case, if editor, which is an object, is just mutated, and that this mutation does not concern it's property editor.view.state.doc, then doc will not be reevaluated. Here are few examples:
this.editor = { ... } // doc will be reevaluated
this.editor.name = ' ... ' // doc will NOT be reevaluated
this.editor.view.state.doc = { ... } // doc will be reevaluated
If you want to understand this under the hood, I would recommand these resources (for Vue 3):
the reactivity course on Vue Mastery (free)
this great talk and demo (building a simple Vue-like reactivity system)
About the inifinite loop, the doc watcher handler will be executed only:
if doc is reassigned with a different value
in the case where docis an object, if doc is mutated (since you applied the deep option to the doc watcher)
The only possibility to trigger an infinite loop would be to, in the doc watcher handler, mutate or give a new value to doc (or editor.view.state.doc). For example (cf #Darius answer):
watch: {
doc: {
handler: function(val, OldVal){
// we give a new ref each time this handler is executed
// so this will trigger an infinite loop
this.editor.view.state.doc = {}
},
// ...
},
}
=> to reply to the second question, apart from these edge cases, your code won't trigger a loop. For example:
watch: {
doc: {
handler: function(val, OldVal){
// even if we mutate the editor object, this will NOT trigger a loop
this.editor.docsList = []
},
// ...
},
}
Changing editor variable should work, but changing Editor content may not, as it depends on Editor class and how it respects reactivity.
For example:
export default {
data: function() {
return {
editor: {text: '' }
}
}
}
...
this.editor.text = 'Text' // works
this.editor.text = {param: ''} // works
this.editor.text.param = 'value' // works
this.editor.param = {} // does't work, as creation of new property is not observable
If editor observer works and you are changing editor property in observer, which 'reinitializes' internal structures, it may lead to infinite loop:
var Editor = function() {
this.document = {}
this.change = () => { this.document = {} }
}
var data = new Vue({
data: () => ({
editor: new Editor(),
check: 0
}),
watch: {
editor: {
handler() {
this.check++
console.log('Changed')
if (this.check < 5)
this.editor.change()
else
console.log('Infinite loop!')
},
deep: true,
immediate: true
}
}
})
data.editor.change()
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
In such case, extra checking is necessary before making the change.

Access component instance from vue watcher

I'm working on a project, similar as a bill manager, so I want that the subtotal get recalculated every time that quantity or unit value change, I have tried and searched to accomplish this using watcher or computed properties, but I don't find the right approach, cause I need to access the whole scope of the element when another change, like this.
Model structure:
detail
quantity
unit value
subtotal (should be a computed or updated)
So I think I should be able of doing something like this:
Vue.component('item', {
template: '#item',
props: {
item: Object,
},
computed:{
total: function(){
return this.quantity*this.unit_value;
}
},
watch:{
'item.quantity':()=>{
this.subtotal = this.quantity*this.unit_value;
}
}
});
I have several components being read from a list
I merged the approach using watcher and computed in the same code to make it shorter.
The problem is that I haven't found a way to access the hole element from inside itself, anyone could pls explain the right way? thanks
You shouldn't use arrows functions there, use method declarations.
If you want to watch for a property of the item object, you'll have to watch for the item object itself, and additionally use the deep: true flag of the watcher.
Final detail, you are using several properties that are not declared in your data. Declare them, otherwise they will not be reactive, that is, the computed will not recalculate when they change.
See code:
Vue.component('item', {
template: '#item',
props: {
item: Object,
},
data() {
return {
subtotal: null, // added data properties
quantity: null,
unit_value: null
}
},
computed: {
total: function() {
return this.quantity * this.unit_value;
}
},
watch: {
item: { // watching for item now
deep: true, // using deep: true
handler() { // and NOT using arrow functions
this.subtotal = this.quantity * this.unit_value;
}
}
}
});

Vuejs deep nested computed properties

I'm not really understanding where to put function() { return {} } and where not to when it comes to deeply nesting computed properties.
By the way, this is in a component!
computed: {
styles: function() {
return {
slider: function() {
return {
height: {
cache: false,
get: function() {
return 'auto';
}
},
width: {
cache: false,
get: function() {
return $('#slideshow').width();
}
}
}
}
}
}
},
This is returning undefined. When I get rid of the function() { return {} } inside of the slider index, it returns an object when I do styles.slider.width instead of the get() return. It just shows an object with cache and get as indexes..
Thanks for any help!
The reason I'm asking is because I have multiple nested components that involve styling from the parent. Slider, tabs, carousels, etc. So I wanted to organize them like this.
I believe you mean to return a computed object, but not actually structure the computation in a nested manner?
What the others have said regarding the 'computed' hook not having syntax for nesting is correct, you will likely need to structure it differently.
This may work for you: I generate many objects in a similar fashion.
computed: {
computedStyles(){
var style = {slider:{}}
style.slider.height = 'auto'
style.slider.width = this.computedSlideshowWidth
return style
},
computedSlideshowWidth(){
return $('#slideshow').width()
}
As per 2020 and Vue 2.6.12 this is completelly possible. I believe this has been possible since v.2 but cannot confirm.
Here is the working example:
this.computed = {
// One level deep nested,
// get these at `iscomplete.experience`
// or `iscomplete.volume`
iscomplete: function() {
return {
experience: this.$data.experience !== null,
volume: this.$data.volume > 100,
// etc like this
};
},
// More levels deep nested.
// Get these at `istemp.value.v1 and `istemp.value.v2`
istemp: function() {
return {
value1: {
v1: this.$data.experience,
v2: 'constant'
}
}
}
};
As a result you will be able to access your deep nested computed in your template as e.g. follows <span v-text="iscomplete.experience"></span> that will output <span>true</span> for the first example computed above.
Note that:
Since Vue v.2 cache key is deprecated;
Vue would not execute functions assigned to a computed object nested keys;
You cannot have computed for non-Vue-reactive things which in your case is e.g. $('#slideshow').width(). This means they are not going to be re-computed on their content change in this case (which is a computed's sole purpose). Hence these should be taken away from computed key.
Other than that I find nested computeds to be quite helpful sometimes to keep things in better order.

trying to derive from a dijit Button: "TypeError: this._attachEvents is undefined"

I am trying to derive an "extended" Button from dijit/Form/Button. (I want to pass extra arguments to the constructor, and I want to encapsulate these preparations in my derived class. Button is just an example, I want to use this later with grids and trees.)
Unfortunately the code below fails with "TypeError: this._attachEvents is undefined" in the firefox javascript console. Some idea, what is wrong? The same code, including minimal HTML, is ready to run at http://jsfiddle.net/x9dLs8gz/1/
require(["dojo/_base/declare", "dijit/form/Button", "dojo/dom", "dojo/json", "dojo/domReady!"],
function (declare, Button, dom, json) {
declare("MyButton", Button, {
"-chains-": {
constructor: "manual"
},
constructor: function () {
//extra calculation will go here...
this.inherited(arguments);
}
});
new MyButton({
label: "Click Me!",
onClick: function () {
dom.byId("result").innerHTML += "Success";
}
}, "button").startup();
});
Cheers,
Dominic
If the "-chains-" value for the constructor method is either not set or set to "after", then the postscript method will be called after all of the inherited constructors have been fired. On the other hand, when specifying "manual", postscript is fired after the first constructor (in this case MyButton#constructor) is executed. As a result, _AttachMixins#buildRendering is fired before this._attachEvents has been set in _AttachMixins#constructor, causing the error you see.
Since specifying "manual" means that no chaining is assumed whatsoever, mixin contructors will never be called, even if this.inherited is correctly called up the chain. This makes sense, as the underlying C3MRO is thrown out the window.
If you need to continue using the "manual" setting in spite of this, you will need to 1) recreate any missing data yourself, 2) manually call the mixin constructors (e.g., _AttachMixin.prototype.constructor.call(this)), or 3) convert MyButton to a factory for Button:
var createButton = (function () {
var myButtonDefaults = { ... };
return function (kwArgs, id) {
var buttonId = id || 'button';
return new Button(lang.mixin({}, myButtonDefaults, kwArgs), buttonId);
};
})();
var myButton = createButton();
myButton.startup();
console.log(myButton instanceof Button); // true
You need to assign the declared class to a variable or declare in a different file and added it to the list of object in the require. Also dont use variable names which are keywords like "constructor". below is the fixed version of your example.
require(["dojo/_base/declare", "dijit/form/Button", "dojo/dom", "dojo/json", "dojo/domReady!"],
function(declare, Button, dom, json) {
var MyButton = declare("MyButton", Button, {
"-chains-": {
constructorType: "manual"
},
constructor: function() {
//extra calculation will go here...
this.inherited(arguments);
}
});
new MyButton({
label: "Click Me!",
onClick: function() {
dom.byId("result1").innerHTML += "Success";
}
}, "button").startup();
});
<div id="button"></div>
<div id="result1"></div>

Define a reusable component

1-I used following code to define a reusable grid,
but when I make instance, no config in class definition either do not have effect of break the code. What is the reason?
3- Is there any restriction in class config declaration?
2- How I can make some default columns in grid class and add some more columns to its objects?
Thanks
Ext.define("IBS.users.Grid", {
extend: "Ext.grid.Panel",
config:{
selType:'checkboxmodel', //not work
dockedItems:[/* items */], //break
multiSelect:true,
features: [
{
groupHeaderTpl: '{name}',
ftype: 'groupingsummary'
},
{
ftype:'filters',
encode: false, // json encode the filter query
local: true
}
],
viewConfig: { //not work
stripeRows: true,
filterable:true,
loadMask: false
},
listeners : {
itemdblclick: function(dv, record, item, index, e) {
console.log(arguments);
}
}
},
constructor:function(config) {
this.callParent(arguments);
this.initConfig(config);
// this.self.instanceCount++;
}
});
1-I used following code to define a reusable grid, but when I make instance, no config in class definition either do not have effect of break the code. What is the reason?
I can answer why your config doesn't have effect. Because config which is being passed into cunstructor is not your default config. You have to apply your default config in order to make default config to have effect:
constructor:function(config) {
config = Ext.applyIf(config, this.config);
this.callParent(arguments);
this.initConfig(config);
}
However, I don't know why dockedItems:[/* items */] breaks the code. Maybe you have syntax or logical errors somewhere within /* items */.
2- How I can make some default columns in grid class and add some more
columns to its objects?
That is easy. Just override your initComponent function:
Ext.define("IBS.users.Grid", {
extend: "Ext.grid.Panel",
// ...
initComponent : function(){
if (!this.columns) {
// default columns:
this.columns = [{
dataIndex: 'dkjgkjd',
// ...
}];
// if we passed extraColumns config
if (this.extraColumns)
for (var i=0; i < this.extraColumns.length; i++)
this.columns.push(this.extraColumns[i]);
}
this.callParent(arguments);
},
// ...
});
3- Is there any restriction in class config declaration?
I'm not aware of any. However, I wouldn't recommend to declare object configs in class definition. For example:
Ext.define("IBS.users.Grid", {
extend: "Ext.grid.Panel",
bbar: Ext.create('Ext.toolbar.Toolbar', // ...
// ...
});
It will be ok with first instance of the class. But when you create the second instance it's bbar refers to the same object as the first instance. And therefore bbar will disappear from the first grid.
Instead declare object configs in initComponent.