I'm trying to build a dynamic Vue system, where I want to insert custom components knowing only their name. Inspiration from here took me to do:
export default {
name: 'MySite',
mixins: [MyMixin],
components: {MyComponent1, MyComponent2},
...
}
...
mounted() {
var ComponentClass = Vue.extend(MyComponent1)
var instance = new ComponentClass()
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
}
Now I want to do the same thing, but knowing only the component name 'MyComponent1' as String. What is the way to do it ? I guess it's more related to pure JavaScript than Vue, but I can't figure out how to do it.
you are right is a simple js.
look at the example below, most importend thing is eval()
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
get getHeight() {
return this.height
}
}
// js string code
var code = "new Polygon(15, 200)";
// convert it to code;
var cls = eval(code);
console.log(cls.getHeight)
I found that using
this.$options.__proto__.components['MyComponent1']
works and do what I want. Is it the cleanest solution ?
Related
I want to port my vue directive to also render server side.
client side:
mydirective(el,binding,vnode){
el.innerText = vnode.context.$data.points
}
What i have working so far in nuxt.config.js:
render: {
bundleRenderer: {
directives: {
mydirective(node, binding){
var points = node.context.$data.points //works
node.data.style = [{backgroundColor: 'green'}] //works
node.data.innerText = points //NOT working
node.data.textContent = points //NOT working
}
I cant find the element reference.
i used the following function to search through the node object:
Object.keys(node).forEach(key=>{
console.log(key)
console.log( node[key])
console.log('============================%%%%%%%%%%%%%%%%%%%%%================================')
})
enter code here
Found it:
mydirective(node, binding){
var points = node.context.$data.points
node.data.domProps = {
innerHTML: points
}
}
documentation: https://v2.vuejs.org/v2/guide/render-function.html#The-Virtual-DOM
I'm learning Vue and have been struggling to get the data from a computed property. I am retrieving comments from the store and them processing through a function called chunkify() however I'm getting the following error.
Despite the comments being computed correctly.
What am I doing wrong here? Any help would be greatly appreciated.
Home.vue
export default {
name: 'Home',
computed: {
comments() {
return this.$store.state.comments
},
},
methods: {
init() {
const comments = this.chunkify(this.comments, 3);
comments[0] = this.chunkify(comments[0], 3);
comments[1] = this.chunkify(comments[1], 3);
comments[2] = this.chunkify(comments[2], 3);
console.log(comments)
},
chunkify(a, n) {
if (n < 2)
return [a];
const len = a.length;
const out = [];
let i = 0;
let size;
if (len % n === 0) {
size = Math.floor(len / n);
while (i < len) {
out.push(a.slice(i, i += size));
}
} else {
while (i < len) {
size = Math.ceil((len - i) / n--);
out.push(a.slice(i, i += size));
}
}
return out;
},
},
mounted() {
this.init()
}
}
Like I wrote in the comments, the OPs problem is that he's accessing a store property that is not available (probably waiting on an AJAX request to come in) when the component is mounted.
Instead of eagerly assuming the data is present when the component is mounted, I suggested that the store property be watched and this.init() called when the propery is loaded.
However, I think this may not be the right approach, since the watch method will be called every time the property changes, which is not semantic for the case of doing prep work on data. I can suggest two solutions that I think are more elegant.
1. Trigger an event when the data is loaded
It's easy to set up a global messaging bus in Vue (see, for example, this post).
Assuming that the property is being loaded in a Vuex action,the flow would be similar to:
{
...
actions: {
async comments() {
try {
await loadComments()
EventBus.trigger("comments:load:success")
} catch (e) {
EventBus.trigger("comments:load:error", e)
}
}
}
...
}
You can gripe a bit about reactivity and events going agains the reactive philosophy. But this may be an example of a case where events are just more semantic.
2. The reactive approach
I try to keep computation outside of my views. Instead of defining chunkify inside your component, you can instead tie that in to your store.
So, say that I have a JavaScrip module called store that exports the Vuex store. I would define chunkify as a named function in that module
function chunkify (a, n) {
...
}
(This can be defined at the bottom of the JS module, for readability, thanks to function hoisting.)
Then, in your store definition,
const store = new Vuex.Store({
state: { ... },
...
getters: {
chunkedComments (state) {
return function (chunks) {
if (state.comments)
return chunkify(state.comments, chunks);
return state.comments
}
}
}
...
})
In your component, the computed prop would now be
computed: {
comments() {
return this.$store.getters.chunkedComments(3);
},
}
Then the update cascase will flow from the getter, which will update when comments are retrieved, which will update the component's computed prop, which will update the ui.
Use getters, merge chuckify and init function inside the getter.And for computed comment function will return this.$store.getters.YOURFUNC (merge of chuckify and init function). do not add anything inside mounted.
I'm trying to create an instance of a QtMobility MapPolyline and several of Coordinate in QML programmaticaly from a Javascript function.
As far as I can see the only way to create new instance from Javascript functions is to use Qt.createComponent and Qt.createQmlObject. However, I can't find a way to call createComponent that will work (I always get a file doesnt exist error). And I'd like to avoid Qt.createQmlObject since it seems like a really bad practice.
Is there any clean way to achieve this?
Component {
id: polyGenerator
MapPolyline {}
}
function addPoly() {
//This next line works, but crashes when trying to add positions
//createPoly(polyGenerator);
var component = Qt.createComponent("Rectangle");
console.log(component.status + " " + Component.Null);
if (component.status == Component.Ready) {
createPoly(component);
} else if (component.status == Component.Error) {
console.log("Error: " + component.errorString());
} else {
component.statusChanged.connect(function () {
if (component.status == Component.Error) {
console.log("Error: " + component.errorString());
return;
}
createPoly(component);
});
}
}
function createPoly(component) {
var poly = component.createObject(map);
poly.border.color = "red";
poly.border.width = 4;
// I get a crash here, my guess is that I need proper Coordinate objects
poly.addCoordinate({latitude: -34.60553, longitude: -58.38088});
poly.addCoordinate({latitude: -34.60720, longitude: -58.38081});
poly.addCoordinate({latitude: 34.60720, longitude: -58.38081});
poly.addCoordinate({latitude: -34.60597, longitude: -58.37930});
map.addMapObject(poly);
}
Qt.createComponent needs a URL to load a file from. That's why it complains about a missing file; you're trying to load a file called "Rectangle".
If you just want to create objects dynamically create your component declarative.
Component {
id: component
Rectangle {
}
}
That way the createPoly function should work fine.
I am actually playing with Javascript doing a small game and I would like to implement what I've found on http://www.crockford.com/javascript/inheritance.html which is something similar to:
ZParenizor.method('toString', function () {
if (this.getValue()) {
return this.uber('toString');
}
return "-0-";
});
I can't find any reference the the library used to make such development possible. Any ideas? Otherwise, I'm looking for a good library that will aid my OOP developments.
Thank you
Edit:
I am looking for a OOP solution / library for Node.js. Please note that I'm new to Node.js
2 months later
Maybe you do need a library, ES5 is verbose as hell so I've created pd
Original answer
I am looking for a OOP solution / library for Node.js.
You don't need a library. You have ES5.
JavaScript does not have classical OOP. It has prototyping OOP.
This means you have only objects. The only thing you can do with objects is extend, manipulate and clone them.
Manipulate
var o = {};
o.foo = "bar";
Extend
var o = someObject;
Object.defineProperties(o, {
"foo": { value: "foo" },
"bar": { value: "bar" }
"method": { value: function () { } }
}
Clone
var o = someObject;
var p = Object.create(o);
Clone and extend
var o = someObject;
var p = Object.create(o, {
"foo": { value: "foo" },
"bar": { value: "bar" }
"method": { value: function () { } }
}
It's important to understand how Object.create, Object.defineProperty and Object.defineProperties work.
The cloning operation isn't actually cloning. It's creating a new object from a blueprint. A blueprint is an object. It places the blueprint in the [[Prototype]]. The [[Prototype]] lives in the .__proto__ property which I'll use for demonstration.
var o = {};
var p = Object.create(o);
p.__proto__ === o; // true
var q = Object.create(p);
q.__proto__.__proto__ === o;
var r = Object.create(q);
r.__proto__.__proto__.__proto__ === o;
Disclaimer: .__proto__ is deprecated. Don't use it in code. It has it's uses for debugging and sanity checks though.
The main point here is that accessing properties from o in r it has to walk 3 levels up the prototype chain and this gets expensive. To solve that problem, rather then cloning random objects you should clone specific blueprints (and you should have one blueprint per object).
// Parent blueprint
var Parent = (function _Parent() {
// create blank object
var self = Object.create({});
// object logic
return self;
}());
// factory function
var createParent = function _createParent(foo) {
// create a object with a Parent prototype
return Object.create(Parent, {
foo: { value: foo }
});
}
var Child = (function _Child() {
var self = Object.create(Parent);
// other stuff
return self;
}());
var createChild = function _createChild(bar) {
return Object.create(Child, {
bar: { value: bar }
})
};
Here's a snippet from some code I'm working on that you can use as an example:
var Sketchpad = (function _SketchPad() {
var self = Object.create({});
var mousemove = function _mousemove(e) {
this.drawLine(e);
};
self._init = function _init() {
this.$elem.bind({
"mousemove": mousemove.bind(this),
});
this.pens = {};
$("#clear").bind("click", this.clear.bind(this));
$("#undo").bind("click", (function _undoPath() {
this.pen.undo();
}).bind(this));
return this;
};
self.clear = function() {
this.paper.clear();
};
return self;
}());
createSketch = function _createSketchPad(id, w, h) {
var paper = Raphael(id, w, h);
var pen = createPen(paper);
var o = Object.create(Sketchpad, {
paper: { value: paper },
$elem: { value: $("#" + id) },
pen: {
get: function() { return pen; },
set: function(v) { pen = v; }
}
});
return o._init();
};
MooTools is one of the best libraries in terms of OOP Javascript.
You can create classes, interfaces, use inheritance, etc.
Documentation
http://mootools.net/docs/core
Tutorial - MooTools OOP
http://www.phpeveryday.com/articles/MooTools-Basic-Creating-Classes-MooTools-P919.html
You might also be interested in GNU ease.js. If you are not interested in the library itself, its manual goes extensively into the implementation details.
You could also see the author's paper on Classical OOP in ECMAScript.
You could try Joose, https://github.com/SamuraiJack/Task-Joose-NodeJS. Although, I'd personally recommend to stick with Javascript's object functionality as provided by ES5.
In the article you referenced, he was simply giving an example of what was possible with inheritance in javascript. He was not using a framework, but showing you how to extend your own classes you have written.
Frameworks for javascript include Backbone.js (mvc), and MooTools (oop).
extjs has support for OOP with Ext.define and Ext.extend (and Ext.ns). See this example on Sencha.com
Ext.extend is the older method, but is still sometimes useful. You would do something like this:
Ext.ns('myApp.myPackage'); // create a namespace
(function() { // this adds it to the namespace
var MyClass = Ext.extend(BaseClass, {
property: 1,
constructor: function(config) {
Ext.apply(this, config);
},
method: function(a, b) {
this.property = a + b;
}
});
myApp.myPackage.MyClass = MyClass;
}) ()
With Ext.define in Ext 4+ you can do:
Ext.define('myApp.myPackage.MyClass', // don't need to define the namespace first
extend: 'BaseClass' // notice the base class is referenced by a string,
requires: 'AnotherClass',
mixins: { mixin : 'MixinPackage' },
property: 1,
constructor: function(config) {
//...
}
method: function(a, b) {
this.property = a + b;
}
});
Note that you can also use traditional OOP in javascript with 'new' and function.prototype
If you want to do a real strong OOP in Javascript/Node, you can have a look at the full-stack open source framework Danf.
It allows you to use OOP (and so the same classes) on both the server (node) and client (browser) sides.
It also provides a nice dependency injection mechanism (looking as the one of Symfony2 if you come from the PHP community).
I'm trying to figure out how ExtJS4 passes around config objects.
I want to do the equivalent of...
store = function(config){
if ( typeof config.call !== 'unndefined' ){
config.url = "server.php?c=" + config.call || config.url;
};
Sketch.Data.AutoSaveStore.superclass.constructor.call(this,config);
};
Ext.extend(store, Ext.data.Store{})
I am probably missing something obvious here, but having dug around in the sandbox file, the closest I have come is....
Ext.define('My.awesome.Class', {
// what i would like to pass.
config:{},
constructor: function(config) {
this.initConfig(config);
return this;
}
});
which doesn't seem to work if you do something like...
var awesome = Ext.create('My.awesome.Class',{
name="Super awesome"
});
alert(awesome.getName()); // 'awesome.getName is not a function'
However
Ext.define('My.awesome.Class', {
// The default config
config: {
name: 'Awesome',
isAwesome: true
},
constructor: function(config) {
this.initConfig(config);
return this;
}
});
var awesome = Ext.create('My.awesome.Class',{
name="Super awesome"
});
alert(awesome.getName()); // 'Super Awesome'
This is biting me in the rear end when trying to do complex store extensions.
Anyone have any idea how I pass a bunch of random params to the prototype?
You should not be using new operator to create new instance on your class. In ExtJS4, you should use Ext.create() method.
Try doing:
var awesome = Ext.create('My.awesome.Class');
alert(awesome.getName());
And if you want to pass some param when creating an instance, you can do the following
var awesome = Ext.create('My.awesome.Class',{name:'New Awesome'});