I'm trying to get a badge to display on one of the navigation tabs.
onClickSetBadge() {
console.log('Button pressed!')
Navigation.mergeOptions(this.props.componentId, {
bottomTab: {
badge: `TeSt`
}
});
}
I'm calling it inside the view I'm rendering.
<ButtonView text='SUP' onPress={() => {this.onClickSetBadge()}} />
The log statement shows up in my console, however, the badge is not shown.
According to the official document: https://wix.github.io/react-native-navigation/#/docs/layout-types?id=updating-options-for-a-specific-tab , that is how it works:
1) Define an id for the specific tab:
stack: {
id: 'CartTab',
children: [{
component: {
name: 'store-cart',
}
}],
options: {
bottomTab: {
text: 'Cart',
icon: require('../asset/image/menu/cart.png'),
}
}
}
2) Use the tab id to update when needed:
Navigation.mergeOptions('CartTab', {
bottomTab: {
badge: cart.length > 0 ? cart.length.toString() : ''
}
});
Related
i have a v-for loop as my selection for dialog boxes I want to open
<v-card #click="page.model = true">
page.model is my v-model for a v-dialog
data() {
return {
dialog1: false,
dialog2: false,
pages: [
{
id: "1",
model: "dialog1",
},
{
id: "2",
model: "dialog2",
},
],
};
},
howcome #click="page.model = true" doesn't work but #click=dialog1 = true " does?
I also tried :#click="page.model = true" and #click="${page.model} = true"
Thank you in advance
So we dont see your modal HTML so I presume something like this:
<v-card v-for="page in pages" #click="changePage(page.id)">
<modal v-model="pages[0].isOpen">[CONTAIN OF PAGE 1]</modal>
<modal v-model="pages[1].isOpen">[CONTAIN OF PAGE 2]</modal>
data() {
return {
pages: [
{
id: "1",
model: "dialog1",
isOpen: false,
},
{
id: "2",
model: "dialog2",
isOpen: false,
},
],
},
methods: {
changePage(id) {
// close all other modal page
this.pages.each(el => el.isOpen = false);
// open the good one
const index = this.pages.findIndex(el => el.id == id);
this.pages[index].isOpen = true;
}
},
I have done something similar. Call a method and pass index of item. In the method you can then access the specific model via index
<v-card #click="updateDialog(index)">
updateDialog(i): {
this.pages[i].model = true
}
The meta data on my website is not updating when the route changes. The route itself has a watch on it which updates the view fine, but the metaInfo() from vue-meta is not keeping up. The <script> section of my code looks like this:
<script>
export default {
name: "Product",
watch: {
'$route.params.ProductID': {
deep: true,
immediate: true,
handler() {
this.getProduct(); // calls getProduct() on route change. Can I also call metaInfo() from here somehow?
}
}
},
metaInfo() {
return {
title: this.Product.ProductTitle,
meta: [
{
name: 'description', content: this.Product.ProductTitle
}
]
}
},
computed: {
Product() {
return this.$store.getters.getProduct
}
}, mounted() {
if (this.Product == null || !this.Product.length) {
this.getProduct();
}
}, methods: {
getProduct() {
return this.$store.dispatch('loadProduct', {ProductID: this.$route.params.ProductID})
}
}
}
</script>
What is happening is that when I change my route and go from /product/123 to /product/124, the metaInfo() still shows the meta data for /product/123. If I hit refresh, then the metaInfo() updates and shows the correct data for /product/124.
I need the watch to trigger an update of metaInfo() but don't know how to do it. I can't find this information in the docs anywhere. Please help?
For reactive, use variables outside return statements.
metaInfo() {
const title = this.Product.ProductTitle;
return {
title: title,
meta: [
{
name: 'description', content: title
}
]
}
}
https://vue-meta.nuxtjs.org/guide/caveats.html#reactive-variables-in-template-functions
I am trying to replicate the TODO MVC in VueJs.
(Please checkout this codepen : http://codepen.io/sankalpsingha/pen/gwymJg )
I have created a component called 'todo-list' with the following code :
Vue.component('todo-list',{
template: '#todo-list',
props: ['todo'],
data: function() {
return {
// Let us set up a isEditing Boolean so that we can know if the user
// will edit something and we need to change the state to reflect it.
isEditing: false,
}
},
methods: {
enableEditing: function() {
this.isEditing = true;
},
editTodo: function(todo) {
// todo.todo = todo.todo.trim();
this.isEditing = false;
},
removeTodo: function(todo) {
//this.todos.$remove(todo); // --> This part is not working?
}
}
});
However, I have the data defined in the app instance :
var app = new Vue({
el: '#todo-section',
data: {
newTodo: '',
todos: [
{
id: 1,
todo: 'Go to the grocery',
completed: false,
},
{
id: 2,
todo: 'See the movie',
completed: true,
},
{
id: 3,
todo: 'Jack Reacher : Tom Cruise',
completed: false,
}
]
},
methods: {
addTodo: function() {
// This will not allow any empty items to be added.
if(this.newTodo.trim() == '') {
return;
}
this.todos.push({
todo: this.newTodo.trim(),
completed: false,
});
this.newTodo = '';
}
}
});
I am not able to delete a single Todo from the list. My guess is that I have to send a emit message to the app instance and put up a listener there to delete the data from it? How do I delete the data?
When I tried to delete by clicking the x button in your codePen example, I see the error: this.$parent.todos.$remove is not a function.
I have not looked deeply into your code. But attempting to access parent component methods using this.$parent is not a good idea. Reason: a component can be used anywhere, and assuming that it will have a $parent with a particular property or method is risky.
As you suggested in your question, you need to use $emit from the child component to delete the data.
There was another similar question here few days ago, for which I created a jsFiddle: https://jsfiddle.net/mani04/4kyzkgLu/
The child component has some code like:
<button #click="$emit('delete-row')">Delete</button>
This sends out an event to parent component. Parent component can subscribe to that event using v-on as seen in that jsFiddle example.
Here is that other question for reference: Delete a Vue child component
It's preferable to use your methods (DeleteTodo, EditTodo...) in your parent.
var app = new Vue({
el: '#app',
data: {
newTodo: '',
todos: [{
id: 1,
title: 'Go to the grocery',
completed: false
}, {
id: 2,
title: 'See the movie',
completed: true
}, {
id: 3,
title: 'Jack Reacher : Tom Cruise',
completed: false
}]
},
methods: {
addTodo: function() {
this.todos.push({
todo: this.newTodo.trim(),
completed: false
});
this.newTodo = ''
},
deleteTodo: function(todo) {
this.todos = this.todos.filter(function(i) {
return i !== todo
})
}
}
});
<div id="app">
<ul>
<li v-for="todo in todos">{{ todo.title }}
<button #click.prevent="deleteTodo(todo)">
Delete
</button>
</li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
I'm having trouble getting data to display in my Vue components. I'm using Vueify and I'm trying to load an array of listings from the listings.vue component and I keep getting errors. Also, I don't understand how to pull in the data via the computed method. Any help would be appreciated.
This is the error I'm getting in the console:
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
[Vue warn]: $mount() should be called only once.
Here is my app.vue
// app.vue
<style>
.red {
color: #f00;
}
</style>
<template>
<div class="container">
<div class="listings" v-component="listings" v-repeat="listing"></div>
</div>
</template>
<script>
module.exports = {
replace: true,
el: '#app',
components: {
'listings': require('./components/listings.vue')
}
}
</script>
Here is my listings.vue component
<style>
.red {
color: #f00;
}
</style>
<template>
<div class="listing">{{title}} <br> {{description}}</div>
</template>
<script>
module.exports = {
data: {
listing: [
{
title: 'Listing title number one',
description: 'Description 1'
},
{
title: 'Listing title number two',
description: 'Description 2'
}
]
},
// computed: {
// get: function () {
// var request = require('superagent');
// request
// .get('/post')
// .end(function (res) {
// // Return this to the data object above
// // return res.title + res.description (for each one)
// });
// }
// }
}
</script>
The first warning means when you are defining a component, the data option should look like this:
module.exports = {
data: function () {
return {
listing: [
{
title: 'Listing title number one',
description: 'Description 1'
},
{
title: 'Listing title number two',
description: 'Description 2'
}
]
}
}
}
Also, don't put ajax requests inside computed properties, since the computed getters gets evaluated every time you access that value.
I'm currently creating a Twitter client as a way of learning to develop for Blackberry 10. I'm currently trying to create a context menu for a custom ListView item, which on selection will show a dialog in the main layout. However, I cannot get the selected list item to call any functions from the parent Page.
Here is the QML from my custom list item:
import bb.cascades 1.0
Container {
property alias avatar: tracker.imageSource
property alias username: txtTweetUser.text
property alias tweetText: txtTweetContent.text
property alias tweetTime: txtTweetTime.text
signal sendReply(string username)
function cout(text) {
console.debug("[DEBUG] " + text);
}
id: itemTweet
preferredWidth: 768;
preferredHeight: 200
// Actions
contextActions: [
ActionSet {
title: "Action Set"
subtitle: "This is an action set."
actions: [
ActionItem {
title: "Reply"
imageSource: "asset:///reply.png"
onTriggered: {
itemTweet.sendReply(txtTweetUser.text);
}
},
ActionItem {
title: "Retweet"
imageSource: "asset:///retweet.png"
},
ActionItem {
title: "Favourite"
imageSource: "asset:///fav.png"
}
]
} // end of ActionSet
] // end of contextActions list
<Layout for the List Item>...
}
}
And for the main QML file:
import bb.cascades 1.0
TabbedPane {
id: tabbedPane
showTabsOnActionBar: true
Tab {
id: tabTimeline
title: "Timeline"
imageSource: "asset:///twitter-white.png"
Page {
id: pageTimeline
signal openReply
signal showNewTweet
function cout(text) {
console.debug("[DEBUG] " + text);
}
function showTweetWindow(username) {
pageTimeline.dialogNewTweet.text = username;
pageTimeline.dialogNewTweet.visible = true;
}
// Title bar
titleBar: TitleBar {
visibility: Overlay
title: "Twitter"
acceptAction: ActionItem {
id: btnNewTweet
title: "+"
ActionBar.placement: ActionBarPlacement.OnBar
onTriggered: {
pageTimeline.cout("action selected");
dialogNewTweet.visible = true;
}
}
}
// Main content
content: Container {
layout: AbsoluteLayout {}
Container {
// Listview for the tweets
ListView {
id: lstTweets
objectName: "lstTweets"
// Components to display the rows
listItemComponents: [
ListItemComponent {
id: listItem
type: "listItem"
TweetItem {
tweetText: ListItemData.content
tweetTime: ListItemData.time
avatar: ListItemData.avatar
username: ListItemData.username
onSendReply: {
cout("Reply selected in parent to " + username);
pageTimeline.showTweetWindow(username);
}
}
}
]
onSelectionChanged: {
}
function itemType(data, indexPath) {
if (indexPath.length == 1) {
return "header";
} else {
return "listItem";
}
}
}
}
DialogNewTweet {
id: dialogNewTweet
visible: false
onShowNewTweet: {
dialogNewTweet.visible = true;
}
}
}
// End container
}
}
... <Other tabs> ...
}
So when the main QML file receives the SendReply signal, it's suppposed to call showTweetWindow(username) which then makes dialogNewTweet visible, but instead I get the error ReferenceError: Can't find variable: pageTimeline. It's definitely a scope issue, but I can't figure out what I'm doing wrong, or if I need to restructure this.
Answer here:
https://community.blackberry.com/message/182467#182467
What I need to achieve is to operate on a list of data, e.g. delete an item using ContextAction in ListItem in QML, then call a C++ method of an object in QmlDocument's contextProperty. here is how I did it:
C++ code:
QmlDocument *qml = QmlDocument::create("accounts.qml");
root = qml->createRootNode<AbstractPane>();
//Here set the context property, accountsManager was already created
qml->setContextProperty("accountsManager", accountsManager);
//Set the model for the list view
ListView* accountsListView = root->findChild<ListView*>("accountsListView");
accountsListView->setDataModel(accountsManager->getDataModel());
QML code:
Page {
content: Container {
ListView {
id: listView
objectName: "accountsListView"
listItemComponents: [
ListItemComponent {
type: "listItem"
StandardListItem{
id: accountItem
title: ListItemData.username
contextActions: [
ActionSet {
deleteAction: DeleteActionItem {
title: "Delete"
onTriggered: {
//it does not work here, "ReferenceError: Can't find variable: accountsManager"
accountsManager.doSometing();
}
}
}
]
}
}
]
function itemType(data, indexPath) {
return "listItem";
}
} // end of ListView
} // end of Container
actions: [
ActionItem {
title: "Add account"
ActionBar.placement: ActionBarPlacement.OnBar
onTriggered: {
//It works fine here
accountsManager.doSomething();
}
}
]
} // end of Page
And another method:
https://community.blackberry.com/message/453794#453794
At the top Page level add the following line to make the label accessible.
Page {
id: topPage
onCreationCompleted: { Qt.topLabel = topLabel; }
Then in the button definition you can reference the Qt.topLabel from within the list.
listItemComponents: [
ListItemComponent {
type: "item"
Button {
text: "Change To Three"
onClicked: {
Qt.topLabel.text = "Three";
}
}
}
]