how to avoid shared variable in Vue's mixin - vuejs2

Having mixin like
var MyMixin = {
methods: {
setupWebsocket: function (wsPath) {
…
Vue.use(
VueNativeSock.default, url,
{
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 3000,
format: 'json',
}
);
this.$socket.onmessage = this.listen;
this.$socket.onopen = this.onOpen;
}
Both onOpen and listen are defined in two different vue’s instances working together on same page and having own onOpen and onmessage each one:
var myApp1 = new Vue({
…
mixin: [MyMixin],
created: function () {
this.setupWebsocket(this.wsPath);
},
methods: {
onOpen: function(){...},
…
}
The problem is $socket is shared and both instances will receive same onOpen and listen coming from the second instance (created later). I need a custom onopen in every instance.

I was able to resolve it this way:
Moving Vue.use outside of the mixin and run it before creating any instance
function setupWebSocket(wsPath){
var port = window.location.port;
var domain = window.location.hostname + (port ? ':' + port : '');
var schema = (port ? 'ws' : 'wss') + '://';
var url = schema + domain + '/stream/' + wsPath;
Vue.use(
VueNativeSock.default, url,
{
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 3000,
format: 'json',
}
);
}
...
setupWebSocket(wsPath); // plain javascript outside component
Above gave me in every vue's instance access to
instance.$options.sockets
which is a Proxy. ($options.sockets was unavailable before)
Then in created of instances I am able to set up custom functions for every component:
instance.$options.sockets.onmessage
instance.$options.sockets.onopen
Final test:
myApp1.$options == myAppB.$options
false
myApp1.$options.sockets == myAppB.$options.sockets
false
myApp1.$socket == myAppB.$socket
true
and now each instance runs its own custom onopen

Related

Vuejs Local Directive Not Binding To Data When Passing A Method To Call

Defining a vuejs directive locally has issues when calling a method when being bound locally.
The problem: on tab/enter, look-up a value and set it based on what comes back (ie; setTimeout is the fake http call). Upon set time out completing, update the compute property.
I am aware of the migration docs says to use an 'eventHub' to communicate
between the directive and the parent component. Is there another way to do this? If you check out the fiddle below, the global directive works perfectly while the local directive fails. I feel like the vm is not being bound properly on the local directive.
Local directive:
new Vue({
el: '#vue',
directive: {
localSomething: {
bind (el, b, n, o) {
$(el).on('keydown', function(e) {
if(e.keyCode == 13 || e.keyCode == 9) {
b.value($(el).val());
}
});
}
}
},
...
Global directive:
Vue.directive('globalSomething', {
bind (el, b, n, o) {
$(el).on('keydown', function(e) {
if(e.keyCode == 13 || e.keyCode == 9) {
b.value($(el).val());
}
});
}
});
Html:
Local: <input v-local-something="doSomething" />
Global: <input v-global-something="doSomething" />
Method:
methods: {
doSomething: function(value) {
let vm = this;
setTimeout(function() {
vm.item.name = value;
});
}
Fiddle here: https://jsfiddle.net/4g1xyy9h/
You have a typo. directive: should be directives:.
Updated fiddle.

call jspdf using vuejs2

How can I call the jsPDF javascript using vuejs?
var doc = new jsPDF();
var specialElementHandlers = {
'#editor': function (element, renderer) {
return true;
}
};
First of all you can create custom directive (Vue.directive) for js pdf.
ex.
<your public directory path>/js_pdf.js
Vue.directive('js-pdf', {
twoWay: true,
priority: 1000,
deep: true,
params: ['pdfvalue', "pdfname"], //Add your require variable
paramWatchers: {
},
bind: function () {
//As per your wish you can set condition
var self = this;
setTimeout(function () {
var doc = new jsPDF()
doc.text(self.params.pdfvalue, 10, 10)
doc.save(self.params.pdfname + '.pdf');
}, 10);
},
update: function (value) {
//As per your requirement you can change data on update method
var self = this;
setTimeout(function () {
}, 10);
},
unbind: function () {
}
});
Now you can include this file in your index.html file and also include jsPDF library
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.4/jspdf.debug.js"></script>
<script src="<your public directory path>/js_pdf.js"></script>
Next you can use this directive with your element
ex.
<input type="hidden" id="editor" v-js-pdf pdfvalue="Hello world how are" pdfname="document">//Here "v-js-pdf" is our custom directive
Currently i have added hidden field and take static value but you can add dynamic value as per your requirement and you can take any other html element as per your requirement

How we get and post api in Titanium alloy?

How can we get and post api in Titanium alloy?
I am having the api of userDetails, I just want that how can i code to get the data from api.
function getUserDetails(){
}
Thanks in advance.
As you mentioned, you are using Titanium alloy.
So another approach be to extend the Alloy's Model and Collection ( which are based on backbone.js concept ).
There are already some implementation at RestAPI Sync Adapter also proper description/usage at Titanium RestApi sync.
I also provide the description and methodology used, in-case link gets broken:
Create a Model : Alloy Models are extensions of Backbone.js Models, so when you're defining specific information about your data, you do it by implementing certain methods common to all Backbone Models, therefor overriding the parent methods. Here we will override the url() method of backbone to allow our custom url endpoint.
Path :/app/models/node.js
exports.definition = {
config: {
adapter: {
type: "rest",
collection_name: "node"
}
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {
url: function() {
return "http://www.example.com/ws/node";
},
});
return Collection;
}
};
Configure a REST sync adapter : The main purpose of a sync adapter is to override Backbone's default sync method with something that fetches your data. In our example, we'll run through a few integrity checks before calling a function to fetch our data using a Ti.Network.createHTTPClient() call. This will create an object that we can attach headers and handlers to and eventually open and send an xml http request to our server so we can then fetch the data and apply it to our collection.
Path :/app/assets/alloy/sync/rest.js (you may have to create alloy/sync folders first)
// Override the Backbone.sync method with our own sync
functionmodule.exports.sync = function (method, model, opts)
{
var methodMap = {
'create': 'POST',
'read': 'GET',
'update': 'PUT',
'delete': 'DELETE'
};
var type = methodMap[method];
var params = _.extend(
{}, opts);
params.type = type;
//set default headers
params.headers = params.headers || {};
// We need to ensure that we have a base url.
if (!params.url)
{
params.url = model.url();
if (!params.url)
{
Ti.API.error("[REST API] ERROR: NO BASE URL");
return;
}
}
//json data transfers
params.headers['Content-Type'] = 'application/json';
switch (method)
{
case 'delete':
case 'create':
case 'update':
throw "Not Implemented";
break;
case 'read':
fetchData(params, function (_response)
{
if (_response.success)
{
var data = JSON.parse(_response.responseText);
params.success(data, _response.responseText);
}
else
{
params.error(JSON.parse(_response.responseText), _response.responseText);
Ti.API.error('[REST API] ERROR: ' + _response.responseText);
}
});
break;
}
};
function fetchData(_options, _callback)
{
var xhr = Ti.Network.createHTTPClient(
{
timeout: 5000
});
//Prepare the request
xhr.open(_options.type, _options.url);
xhr.onload = function (e)
{
_callback(
{
success: true,
responseText: this.responseText || null,
responseData: this.responseData || null
});
};
//Handle error
xhr.onerror = function (e)
{
_callback(
{
'success': false,
'responseText': e.error
});
Ti.API.error('[REST API] fetchData ERROR: ' + xhr.responseText);
};
for (var header in _options.headers)
{
xhr.setRequestHeader(header, _options.headers[header]);
}
if (_options.beforeSend)
{
_options.beforeSend(xhr);
}
xhr.send(_options.data || null);
}
//we need underscore
var _ = require("alloy/underscore")._;
Setup your View for Model-view binding : Titanium has a feature called Model-View binding, which allows you to create repeatable objects in part of a view for each model in a collection. In our example we'll use a TableView element with the dataCollection property set to node, which is the name of our model, and we'll create a TableViewRow element inside. The row based element will magically repeat for every item in the collection.
Path :/app/views/index.xml
<Alloy>
<Collection src="node">
<Window class="container">
<TableView id="nodeTable" dataCollection="node">
<TableViewRow title="{title}" color="black" />
</TableView>
</Window>
</Alloy>
Finally Controller : Binding the Model to the View requires almost no code at the controller level, the only thing we have to do here is load our collection and initiate a fetch command and the data will be ready to be bound to the view.
Path :/app/controllers/index.js
$.index.open();
var node = Alloy.Collections.node;
node.fetch();
Further reading :
Alloy Models
Sync Adapters
Hope it is helpful.
this is the solution for your problem:-
var request = Titanium.Network.createHTTPClient();
var done=false;
request.onload = function() {
try {
if (this.readyState == 4 && !done) {
done=true;
if(this.status===200){
var content = JSON.parse(this.responseText);
}else{
alert('error code' + this.status);
}
}
} catch (err) {
Titanium.API.error(err);
Titanium.UI.createAlertDialog({
message : err,
title : "Remote Server Error"
});
}
};
request.onerror = function(e) {
Ti.API.info(e.error);
};
request.open("POST", "http://test.com");
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
request.send({ test: 'test'});
if you don't get your answer please let me know.
Thanks

Durandal, get path of the current module

Is there a way in Durandal to get the path of the current module? I'm building a dashboard inside of a SPA and would like to organize my widgets in the same way that durandal does with "FolderWidgetName" and the folder would contain a controller.js and view.html file. I tried using the getView() method in my controller.js file but could never get it to look in the current folder for the view.
getView(){
return "view"; // looks in the "App" folder
return "./view"; // looks in the "App/durandal" folder
return "/view"; // looks in the root of the website
return "dashboard/widgets/htmlviewer/view" //don't want to hard code the path
}
I don't want to hardcode the path inside of the controller
I don't want to override the viewlocator because the rest of the app still functions as a regular durandal spa that uses standard conventions.
You could use define(['module'], function(module) { ... in order to get a hold on the current module. getView() would than allow you to set a specific view or, like in the example below, dynamically switch between multiple views.
define(['module'], function(module) {
var roles = ['default', 'role1', 'role2'];
var role = ko.observable('default');
var modulePath = module.id.substr(0, module.id.lastIndexOf('/') +1);
var getView = ko.computed(function(){
var roleViewMap = {
'default': modulePath + 'index.html',
role1: modulePath + 'role1.html',
role2: modulePath + 'role2.html'
};
this.role = (role() || 'default');
return roleViewMap[this.role];
});
return {
showCodeUrl: true,
roles: roles,
role: role,
getView: getView,
propertyOne: 'This is a databound property from the root context.',
propertyTwo: 'This property demonstrates that binding contexts flow through composed views.',
moduleJSON: ko.toJSON(module)
};
});
Here's a live example http://dfiddle.github.io/dFiddle-1.2/#/view-composition/getView
You can simply bind your setup view to router.activeRoute.name or .url and that should do what you are looking for. If you are trying to write back to the setup viewmodels property when loading you can do that like below.
If you are using the revealing module you need to define the functions and create a module definition list and return it. Example :
define(['durandal/plugins/router', 'view models/setup'],
function(router, setup) {
var myObservable = ko.observable();
function activate() {
setup.currentViewName = router.activeRoute.name;
return refreshData();
}
var refreshData = function () {
myDataService.getSomeData(myObservable);
};
var viewModel = {
activate: activate,
deactivate: deactivate,
canDeactivate: canDeactivate
};
return viewModel;
});
You can also reveal literals, observables and even functions directly while revealing them -
title: ko.observable(true),
desc: "hey!",
canDeactivate: function() { if (title) ? true : false,
Check out durandal's router page for more info on what is available. Also, heads up Durandal 2.0 is switching up the router.
http://durandaljs.com/documentation/Router/
Add an activate function to your viewmodel as follows:
define([],
function() {
var vm = {
//#region Initialization
activate: activate,
//#endregion
};
return vm;
//#region Internal methods
function activate(context) {
var moduleId = context.routeInfo.moduleId;
var hash = context.routeInfo.hash;
}
//#endregion
});

keeping one instance of a dojo module

Is there a way to have a static variable in a dojo (1.8) module so that I can retain state?
Example, say I set some value in some/module
require([
'some/module'
], function (module) {
module.setSomeValue(3);
});
.. and then want to retrieve it later
define([
'some/module'
], function(module) {
return {
start: function() {
var x = module.getSomeValue();
}
};
});
A solution that works but seems like a hack,
acompany = window.acompany || {};
acompany.project = acompany.project || {
};
require([
], function() {
var debug = false;
acompany.project.module = {
/* static variables and functions here */
};
});
define([
], function () {
return acompany.project.module;
});
Actually there is always only single instance of AMD module, because (source):
define has two additional important characteristics that may not be immediately obvious:
Module creation is lazy and asynchronous, and does not occur immediately when define is called. This means that factory is not executed, and any dependencies of the module will not be resolved, until some running code actually requires the module.
Once a module value has been entered into the module namespace, it is not recomputed each time it is demanded. On a practical level, this means that factory is only invoked once, and the returned value is cached and shared among all code that uses a given module. (Note: the dojo loader includes the nonstandard function require.undef, which undefines a module value.)
In addition you do not have to provide just factory function, you can provide an object literal as well:
define("some/module", {
someValue: "some",
otherValue: "other"
});
Then somewhere else in your code:
require(["some/module"], function(module) {
console.log("module.someValue", module.someValue); // some
module.someValue = "some changed";
});
require(["some/module"], function(module) {
console.log("module.someValue", module.someValue); // some changed
});
More robust solution includes an instance of dojo/Stateful, so you can watch for changes and define custom setters and getters:
define("some/stateful-module", ["dojo/Stateful"], function(Stateful){
var stateful = new Stateful({
someValue: "some",
otherValue: "other"
});
return stateful;
});
Then somewhere else in your code:
require(["some/stateful-module"], function(module) {
console.log("stateful-module.someValue:", module.get("someValue"));
module.watch(function(name, oldValue, newValue) {
console.log("stateful-module: property"
, name
, "changed from"
, "'" + oldValue + "'"
, "to"
, "'" + newValue + "'"
);
});
});
require(["some/stateful-module"], function(module) {
module.set("someValue", "some changed");
});​
See how it works at jsFiddle: http://jsfiddle.net/phusick/fHvZf/. It's in a single file there, but it will work the same way across the whole application unless you require.undef(mid) the module.
There are multiple files in Dojo like dojo/date/locale that define static variables and functions and not widgets/classes using dojo.declare.
Define the module
define([
'dojo/_base/lang/',
'some/module'
], function(lang, module) {
var m = lang.getObject('some.module', true);
m.x = 0;
m.doSomething = function(){
// doSomething
};
return m;
});
Use the module
require([
'some/module'
], function(someModule) {
var debug = false;
/* someModule - static variables and functions here */
if(someModule.x == 0){
}
});