Path wildcards in $route.path - vue.js

In my application toolbar I want to show a back button when the user is on /manage/*. If a user is on /manage or /other the back button should not show.
Here's my computed property to return true:false if the user is on /manage/*
computed: {
showBackButton: function() {
return this.$route.path === "/manage/*";
}
}
The wildcards in the regex documentation on the vue-router site do not seem the work. According to the documentation, * is the correct wildcard to use.

Your code is making a type and value comparison, javascript does not work with regex by default... If you want to work with regex, I would rather try something like:
computed: {
showBackButton: function() {
return this.$route.path.match(/^\/manage\/.*$/);
}
}

Related

Event only firing as inline JS statement

I have the following code in a Nuxtjs app in SSR mode.
<Component
:is="author.linkUrl ? 'a' : 'div'"
v-bind="!author.linkUrl && { href: author.linkUrl, target: '_blank' }"
#click="author.linkUrl ? handleAnalytics() : null"
>
The click event in case it's an a tag, will only fire if it's written as handleAnalytics(), but handleAnalytics will not work.
Don't get me wrong the code is working, but I don't understand why.
With classical event binding (#click="handleAnalytics), Vue will auto bind it for you because it sees it's a function.
But when provided a ternary condition, it's not auto binded but wrapped into a anonymous function instead. So you have to call it with parenthesis otherwise you're just returning the function without executing it.
To be clearer, you can write it this way: #click="() => author.linkUrl ? handleAnalytics() : null"
Note: when having a dynamic tag component, I'd suggest to use the render function instead.
This is an advanced technique, but this way you won't bind things to an element that doesn't need it (without having the kind of hack to return null).
Example:
export default {
props: {
author: { type: Object, required: true },
},
render (h: CreateElement) {
const renderLink = () => {
return h('a', {
attrs: {
href: author.linkUrl,
target: '_blank',
},
on: {
click: this.handleAnalytics
},
)
}
const renderDiv = () => {
return h('div')
}
return this.author.linkUrl ? renderLink() : renderDiv()
}
}
Documention: Vue2, Vue3
In javascript functions are a reference to an object. Just like in any other language you need to store this reference in memory.
Here are a few examples that might help you understand on why its not working:
function handleAnalytics() { return 'bar' };
const resultFromFunction = handleAnalytics();
const referenceFn = handleAnalytics;
resultFromFunction will have bar as it's value, while referenceFn will have the reference to the function handleAnalytics allowing you to do things like:
if (someCondition) {
referenceFn();
}
A more practical example:
function callEuropeanUnionServers() { ... }
function callAmericanServers() { ... }
// Where would the user like for his data to be stored
const callAPI = user.preferesDataIn === 'europe'
? callEuropeanUnionServers
: callEuropeanUnionServers;
// do some logic
// ...
// In this state you won't care which servers the data is stored.
// You will only care that you need to make a request to store the user data.
callAPI();
In your example what happens is that you are doing:
#click="author.linkUrl ? handleAnalytics() : null"
What happens in pseudo code is:
Check the author has a linkUrl
If yes, then EXECUTE handleAnalytics first and then the result of it pass to handler #click
If not, simply pass null
Why it works when you use handleAnalytics and not handleAnalytics()?
Check the author has a linkUrl
If yes, then pass the REFERENCE handleAnalytics to handler #click
If not, simply pass null
Summary
When using handleAnalytics you are passing a reference to #click. When using handleAnalytics() you are passing the result returned from handleAnalytics to #click handler.

how to make row disabled with ag-grid?

I work with ag-grid and i found how to make a column disabled in the doc (https://www.ag-grid.com/documentation-main/documentation.php)
but after reading doc i never find how can i make juste one row disabled.
i have already try editable: params => params.data.active === true.
Maybe i didn't read right or that doesn't exist. Is someone here with some soluce track ?
TL;DR
There is no option in the library to make a single row disabled(both visually and keyboard event based), the only way we could make a single row disabled is by using a customCellRenderer for both header and subsequent cell checkboxes, this allows full control over the checkbox.
Besides this, there are three other ways where you can disable ag-grid checkbox based on value,
1)This is using checkBoxSelection param, it would empty the cell based on the condition.
checkboxSelection = function(params) {
if (params.data.yourProperty) {
return true;
}
return false;
}
This would only disabled click events and style it accordingly,
cellStyle: params => return params.data.status? {'pointer-events': 'none', opacity: '0.4' } : '';
3)This would disable it completely, as you have control over the input, but you may have to use string literals,
cellRenderer: (params) => {
if (params.value) {
return `<input type="checkbox" checked/>`;
}
else {
return `<input type="checkbox" />`;
}
}
You could use customCellRenderer(customCellRendererParams for props), headerCellRenderer(headerCellRendererParams for props) which accepts a complete JSX component.
I think this would be the most helpful, it allows you to choose the cellRenderer component based on the row value for that column. Its very well described in the ag-grid documentation.
I think ag-grid has single row checkbox disablement available natively: https://www.ag-grid.com/angular-data-grid/row-selection/#example-forcing-checkboxes-as-selected

You may have an infinite update loop in a component render function using click event conditional rendering

I am rendering two texts based on a condition and be able to pass methods to the click event based on the condition. The default text is ADD TO COLLECTION because initially hasPaid property is false. Once payment has been made, I want to set that property to true
The function addToCollection first opens a modal, on the modal, the handlePayment function is implemented. I have been able to conditionally render the div to show either ADD TO COLLECTION or DOWNLOAD using v-on="". I also return hasPaid property from the handlePayment function.
<div class="float-right peexo-faded-text card-inner-text" :face="face" v-on="!hasPaid ? {click: addToCollection} : {click: handleDownload(face)}">
{{!hasPaid ? 'ADD TO COLLECTION': 'DOWNLOAD' }}
</div>
data: function () {
return {
hasPaid: false,
}
},
addToCollection(){
this.showcollectionModal = true;
},
handlePayment(){
this.showcollectionModal = false;
let accept = true;
this.showpaymentsuccessmodal = true;
//this.hasPaid = true;
return {
hasPaid: accept
}
},
I want to be able to set hasPaid property on the handlePayment function for the render function to pick it, so that the handleDownload function can then work.
The last section of this bit is going to be problematic:
v-on="!hasPaid ? {click: addToCollection} : {click: handleDownload(face)}"
When hasPaid is true it will invoke the method handleDownload immediately. That is, it will be called during render, not when the <div> is clicked.
You could fix it by 'wrapping' it in a function:
{click: () => handleDownload(face)}
I've used an arrow function in my example but you could use a normal function if you prefer.
Personally I wouldn't try to do this using the object form of v-on.
My first instinct is that you should consider just having two <div> elements and use v-if to decide which one is showing.
If you did want to use a single <div> I would put the click logic in a method. So:
<div class="..." :face="face" #click="onDivClick(face)">
Note that despite the apparent syntactic similarity to the way you defined your click listener this won't invoke the method immediately.
Then in the methods for the component:
methods: {
onDivClick (face) {
if (this.hasPaid) {
this.handleDownload(face)
} else {
this.addToCollection()
}
}
}

Vue-Native checkbox change value

I want to be able to change the value of a checkbox by clicking on it. recentContacts are loading just fine, and specifying initial checked values in the computed function works well. The :on-press seems to change the value but does not reflect in the UI.
Please Help
Template
<nb-list>
<nb-list-item v-for="contact in recentContacts" v-bind:key="contact.uid">
<nb-checkbox :on-press="() => contact.checked =! contact.checked" :checked="contact.checked"></nb-checkbox>
<nb-text>{{contact.firstName}} {{contact.lastName}}</nb-text>
</nb-list-item>
</nb-list>
Code
export default {
computed: {
recentContacts() {
return store.state.admin.userData.recentContacts.map(rc => {
rc.checked = false;
return rc;
});
}
},
}
EDIT:
I am guessing because VUEX is imutable. I've got this to work by having recentContacts inside of the data attribute instead of computed just not how I want to do things.

WinJS Listview shows undefined when navigating quickly

I have a WinJS application with listviews in which if quickly navigate between pages before the listview is fully loaded, the next page shows the listview with all elements in it bound as "undefined".
So say I have a hub page with a "to do" that is filtered to only show 6 items, and there is a header that navigates to the full "to do" page, when the hub page is displayed but before it is fully loaded I click on the header link to the "to do" page, the app then goes to the "to do" page, but the items show up with all the properties in the tile as "undefined".
I am using IndexedDB as my data store.
My home page code looks like this:
WinJS.UI.Pages.define("/pages/home/home.html", {
ready: function (element, options) {
WinJS.Utilities.query("a").listen("click", function (e) {
e.preventDefault();
WinJS.Navigation.navigate(e.currentTarget.href);
}, false);
viewModel = new HomeViewModel(element);
viewModel.load(); //loads from indexed db
},
//etc...
To Do Page:
WinJS.UI.Pages.define("/pages/ToDo/ToDo.html", {
ready: function (element, options) {
viewModel = new ToDoViewModel(element);
viewModel.load();
},
etc//
I know there isn't much to go off, but any ideas would be appreciated.
Also tips on how to debug something like this would be great.
Update
I narrowed it down to this one line from the Hub Page:
myLib.GetData(todaysDate, function (result) {
that.trendsModel.today = result;
WinJS.Binding.processAll(that.el.querySelector("#dataPanel"), that.trendsModel); //<--Right Here
});
If I remove that, then when I load the second page the data doesn't show as undefined. What is interesting is the data initially shows correctly on the second page and then it changes to "undefined".
Solution
My fix:
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it changes to undefined...Wow, what a doozy. I guess it makes sense but what a pain to find.
Hope it helps someone in the future :)
Your ToDoViewModel, and HomeViewModel need to be observable. This means they need to mix in from WinJS.Binding.mixin, and for the properties that you pull in asynchronously, they need to call this.notify("propertyName", newVal, oldVal) from the property setter.
Note that you need to have getter/setter properties. e.g.
var bindingBase = WinJS.Class.mix(function() {}, WinJS.Binding.mixin);
WinJS.Namespace.define("YourNamespace", {
ToDoViewModel: WinJS.Class.derive(bindingBase, function constructor() {
}, {
_titleStorage: "",
title: {
get: function() { return this._titleStorage; },
set: function(newValue) {
if(newValue === this._titleStorage) {
return;
}
var old = this._titleStorage;
this._titleStorage = newValue;
this.notify("title", newValue, old);
}
}
}),
});
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it change to undefined...Wow, what doozy. I guess it makes sense but what a pain to find.