QML elements undefined from js - javascript

I have a problems changing elements properties from js file. In my program I have main element with that structure:
import "main.js" as Main
ApplicationWindow
{
id: applicationWindow
VK {
id: vk
onReplyReady: {
if (typeof document === "string") {
var obj = JSON.parse(document)
console.log(typeof obj.response,typeof obj.count)
Main.processReply(obj.response)
} else {
Debug.log("VK UNKNOWN ERROR")
}
}
}
initialPage: Component { Auth { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
}
In the component Auth I have that code:
Page {
id: messangesPage
Button {
id: mycoolbutton
text: "button"
onClicked: {
vk.getMessanges("lol",0)
}
}
Component.onCompleted: {
vk.getMessanges("lol",0)
}
}
So the idea of my code is pretty simple - I have vk object, that must be global. When I call vk.getMessanges, vk send request to the server and after that emit replyReady signal. In onReplyReady I just parse the reply from server and call function in main.js, where I want to execute that function:
function processReply(reply) {
mycoolbutton.text = "mycoolbutton"
}
However I got an error:
main.js:8: ReferenceError: mycoolbutton is not defined
I noticed that if I call processReply() function from component Auth, than everything works fine, but when I call from element applicationWindow than I got that error. I tried to add property alias mycoolbuttonptr : mycoolbutton in the applicationWindow, but I got another error. What I must do in that case?

Are you aware that main.js is instantiated once for every import you make? If you import main.js from several QML files, you are getting several instances of Main, so if you set a reference to mycoolbutton in one of that instances, that reference is only set on that instance.
If you want to have only one Main instance, you have to declare it at the begining of the JS file with
.pragma library

You can't access Items by id from JS file. You should pass button as parameter, for example:
function processReply(reply, btn) {
btn.text = "mycoolbutton"
}
".pragma library" can be helpful, but doesn't solve problem.

Related

How to resolve a type error in javascript/cypress

I am learning cypress and javascript and have come across this type error.
TypeError: _testElements.default.selectionRow is not a function
I looked at some documentation with cypress and can't see a mistake I am making in the code, so was hoping someone with javascript and cypress experience may know why this error is being outputted.
Code:
First the class where it gets the element:
class testElements {
selectionRow() {
return cy.get('.selectionRow')
}
typeButton() {
return cy.get('.typeButton')
}
}
export default testElements
And then the code it's referring the error to is below:
import { Given, When, Then } from "cypress-cucumber-preprocessor/steps";
import testElements from '../elements/testElements';
When ("User selects a row", () => {
testElements.selectionRow()
.within(() => {
testElements.typeButton().not(".disabled");
})
})
You should first create a class instance to use the methods:
const testElem = new testElements();
testElem.selectionRow()
And I suggest to use uppercase name convention for class TestElements.
If you don't want to instantiating the class, you can use static methods

Vue.JS import custom module

I have created a module greatings.js like this one:
function greatings() {
this.hello = function() {
return 'hello!';
}
this.goodbye = function() {
return 'goodbye!';
}
}
module.exports = greatings;
Then I imported it into main.js in VUE.JS just like:
import greatings from './assets/js/greatings';
Vue.use(greatings);
Now I would like to use it in my components but if I do it I got an error:
mounted() {
this.greatings.hello();
}
ERROR: Error in mounted hook: "TypeError: Cannot read property 'hello' of undefined"
How to fix it and be able to use my greatings?
Thanks for any help!
greatings.js file should be like this
export default {
hello() {
return "hello";
},
goodbye() {
return "goodbye!";
}
};
and import in any file you want to use like this
import greatings from './assets/js/greatings';
and call any function do you want. remove this function Vue.use(greatings);
When using Vue.use() to register a custom plugin, it has to define an install() function, which is called by Vue. From docs:
A Vue.js plugin should expose an install method. The method will be called with the Vue constructor as the first argument, along with possible options.
See the provided example, for all the options you have when creating a custom plugin: https://v2.vuejs.org/v2/guide/plugins.html

How to execute certain code after a computed property has been evaluated?

I have a component which checks the endpoint parameter in the URL and then finds the server that contains the said parameter from inside an array with servers. I am trying to execute this code every time the server computed property is evaluated:
this.$store.dispatch('joinServer', this.server)
this.$store.commit('setSelectedServer', this.server)
I do this by adding watchers. Whenever the route URL changes, the computed server property also changes and I watched for those changes and executed the code like this:
watch: {
$route(to, from) {
this.serverEndpoint = this.$route.params.endpoint
},
server(newServer){
this.$store.dispatch('joinServer', newServer)
this.$store.commit('setSelectedServer', newServer)
}
}
The problem is that with my code, whenever I render the component the first time, the code doesn't execute. If I change the URL endpoint, my watchers take effect and the code does get executed.
So what I'm asking is how can I execute the code after the server computed property is evaluated the first time after I visit the component?
My code:
<script>
import ServerRooms from '../components/ServerRooms'
import Chat from '../components/Chat'
import Members from '../components/Members'
export default {
components: {
ServerRooms,
Chat,
Members
},
data(){
return {
serverEndpoint: this.$route.params.endpoint
}
},
computed: {
server(){
return this.$store.state.servers.find((server) => {
return server.endpoint == '/' + this.serverEndpoint
})
}
},
watch: {
$route(to, from) {
this.serverEndpoint = this.$route.params.endpoint
},
server(newServer){
this.$store.dispatch('joinServer', newServer)
this.$store.commit('setSelectedServer', newServer)
}
}
}
</script>
Try using the immediate keyword when defining your watcher. See vue docs on watch
the callback will be called immediately after the start of the
observation
E.g.
watch: {
server: {
handler(newServer){
console.log('newServer = ' + newServer);
this.$store.dispatch('joinServer', newServer)
this.$store.commit('setSelectedServer', newServer)
},
immediate: true
}
}

How To import sanitize.js to react apps Function / class not found

I've some problem, in my project I need to add Sanitize.js on my project, I've copied to my own 3rd party folder ex vendor
to import it I'm using
import {san} from '../../vendor/Sanitize' //There's No error when compiling this one
but there's an error when I run the page, I'm trying to call the function from Sanitize.js as in readme saying to use it just do like this
var s = new san.Sanitize({
elements: ['a', 'span'],
attributes: {
a: ['href', 'title'],
span: ['class']
},
protocols: {
a: { href: ['http', 'https', 'mailto'] }
}
});
s.clean_node(p);
The Error is
san.Sanitize is not a function/ class constructor
Any idea why this is happening? or did I miss something? There's no Error in compiling process, the error only occurs when I try to run the web page,
Because Sanitize.js is not a module.
Maybe you can try the following solution:
Add export default Sanitize; in end of sanitize.js.
Use import Sanitize from "./sanitize"; to import it.
Remove the following code from sanitize.js.
if ( typeof define === "function" ) {
define( "sanitize", [], function () { return Sanitize; } );
}

Global variables Ionic 2

I'm having some difficulties with Ionic 2 and setting up global variables. The structure of my app is as follows:
Main app
|
|--- Page1 (Info)
|--- Page2 (Map)
|--- Page3 (List)
|
|--- ItemTabsPage
|
|---tab1
|---tab2
|---tab3
My intention is to show a list in Page3, and once one item is selected, to show additional information in tabs.
I send the information from Page 3 to the page with the tabs using:
itemTapped(event, item) {
this.nav.push(ItemTabsPage, {
item: item
});
}
The problem is that I can't do the same to send the info to the child tabs. I would like to show different information depending on which item is selected. I have tried defining an injectable globalVars.js to store the value in a variable:
import {Injectable} from 'angular2/core';
#Injectable()
export class GlobalVars {
constructor(myGlobalVar) {
this.myGlobalVar = "";
}
setMyGlobalVar(value) {
this.myGlobalVar = value;
}
getMyGlobalVar() {
return this.myGlobalVar;
}
}
and then updating the code of itemTapped in the list as follows:
itemTapped(event, item) {
this.nav.push(ItemTabsPage, {
item: item
});
this.globalVars.setMyGlobalVar(item);
}
However, I always get the same error:
Uncaught EXCEPTION: Error during evaluation of "click"
ORIGINAL EXCEPTION: TypeError: Cannot read property 'setMyGlobalVar' of undefined
The code for page3 is:
import {Page, NavController, NavParams} from 'ionic-angular';
import {ItemService} from '../services/ItemService';
import {ItemTabsPage} from '../item/item-tabs/item-tabs';
import {GlobalVars, setMyGlobalVar} from '../../providers/globalVars';
import {Http} from 'angular2/http';
import 'rxjs/add/operator/map';
#Page({
templateUrl: 'build/pages/item-list/item-list.html',
providers: [ItemService]
})
export class ItemListPage {
static get parameters() {
return [[NavController], [NavParams], [Http]];
}
constructor(nav, navParams, http, globalVars) {
this.nav = nav;
// If we navigated to this page, we will have an item available as a nav param
this.selectedItem = navParams.get('item');
this.http = http;
//this.items = null;
this.globalVars = globalVars;
this.http.get('https://website-serving-the-info.com/items.json').map(res => res.json()).subscribe(data => {
this.items = data.items;
},
err => {
console.log("Oops!");
});
}
itemTapped(event, item) {
this.nav.push(ItemTabsPage, {
item: item
});
this.globalVars.setMyGlobalVar(item);
}
}
Anyone have any suggestion? My Ionic installation is:
Cordova CLI: 6.1.1
Gulp version: CLI version 3.9.1
Gulp local: Local version 3.9.1
Ionic Framework Version: 2.0.0-beta.4
Ionic CLI Version: 2.0.0-beta.25
Ionic App Lib Version: 2.0.0-beta.15
OS: Distributor ID: LinuxMint Description: Linux Mint 17.3 Rosa
Node Version: v5.11.0
The easiest way I use is to create a file app/global.ts
export var global = {
myvar : 'myvar 01',
myfunction : function(msg) {
alert(msg);
}
};
Then import and use freely in other classes:
import {global} from "../../global";
constructor() {
global.myfunction('test');
}
and if you want to use this global to component HTML page as below
export class HomePage {
Global: any = Global;
now it is available in HTML as below
<div [style.display]="Global.splash ? 'flex': 'none'" >
You're on the right track. And some of the other answers will work, but the Ionic team is recommending you not use globals via a globals file. Instead, they recommend the use of Providers (as you're attempting to do).
You're provider is missing the actual variable declaration.
#Injectable()
export class GlobalVars {
myGlobalVar: string = '' // this is the line you're missing
constructor(myGlobalVar) {
this.myGlobalVar = "";
}
}
You should also note that you are not exporting the function setMyGlobalVar(). You are exporting the class GlobalVars which contains the function setMyGlobalVar().
I believe if you make those changes it should work.
edit
I'd also be careful of this line this.globalVars = globalVars; in your Page3. This will cause a rewrite of your globalVars each time Page3 is created.
I have exactly the same scenario, and would like to share my approach.
my understanding is that, in ionic2, the injection is implemented as instance. which means each time you enter a page, a new instance of the injection is created.
so direct access to a static value does not fit here; you have to somehow bridge the gap.
my approach goes as this:
you still defined a static value in your service provider, yet you define instance "getter", and "setter" for that value.
in your page implementation, you inject the service as a parameter of the constructor.
in the constructor, you have to "new" an instance of the service; and call the "getter", and "setter". see my code snippets below:
export class TransSender {
static _count:number = 0;
static _pushed:number = 0;
...
public static setter(count:number, pushed:number,...) {
TransSender._count = count;
TransSender._pushed = pushed;
}
public get count(){
return TransSender._count;
}
public get pushed(){
return TransSender._pushed;
}
...
}
I actually provide a static collective setter for the service to get value from backend in a static way.
my page implementation runs likes this
import {TransSender} ...;
#Component({
templateUrl: 'build/pages/basics/basics.html',
providers: [TransSender]
})
export class Page {
...
constructor(tSender: TransSender,...) {
...
tSender = new TransSender();
TransSender.setter(1,2,3,4,5,6,7,8);
console.log(tSender.count);
}
}
in your display (html), your will refer to tSender rather than TransSender
this might look a bit stupid. yet I can not find any other solution.
with the release of ionic2 Beta9, bootstrap was re-introduced into the frame. so I am exploring new possibilities
cheers
In your class ItemListPage, try this static parameters method before your constructor:
static get parameters() {
return [[NavController], [NavParams], [Http], [GlobalVars]];
}
I am thinking that you are setting your globalVars variable in the constructor to 'undefined' and therefore you cannot call a function on something that is undefined.
You seem to inject the GlobalVars provider incorrectly in ItemLisyPage.

Categories