Dynamic Selection Method of QDataTable quasar-framework vue-js - vue.js

I have a list of collapsible’s in a v-for, and a QDataTable component inside with multiple selection as below.
<q-collapsible :label="req.label" v-for="(req, index) in requisitions" :key="index" class="collapsible-no-padding requisitionContainer" #open="openRequisition('Requisition' + req.reqId)" #close="closeRequisition('Requisition' + req.reqId)" :id='"Requisition" + req.reqId'>
<q-list>
<q-item link class='ordersContainer'>
<q-item-main>
<q-data-table
:data="req.filteredOrdersList"
:config="orderConfigs"
:columns="orderColumns"
#selection="selectOrders">
</q-data-table>
</q-item-main>
</q-item>
</q-list>
</q-collapsible>
It looks like this
However, since there are more than one table, if a selection is made on any of the tables, it does call the selection method with the selected item, but I have no way to tell which table it is a part of. This is a problem when a selection is removed and you are returned an empty array, for which I need to distinguish between each tables selection event. Is there a way to do it?

You can pass the reference to the req object to the method in the #selection handler.
Since you also need the reference to the array of selected items currently being implicitly passed to the selectOrder method, you'll now need to explicitly pass that value. Normally, you could do that via the $event variable accessible inline.
However, contrary to the documentation, the <q-data-table> component's selection event is emitting two variables: the count of the elements in the array of selected items, and the array of selected items itself, in that order.
To get a reference to the array of selected items, you'll need to access the second argument being emitted via arguments[1]:
#selection="selectOrders(arguments[1], req)"

Related

How to handle changing props inside a component

I'm making a Form wrapper and I'm wondering how to handle data object prop.
From what I have seen out there, there are some (like FormKit) that mutate the prop object that holds the data. This is not a recommended way according to the official docs. Then there are those (like VueFormulate) that create a shallow copy of the data object before emiting the changed object. To support nested data object you need to deep copy the data object on every change. This seems wasteful with large forms.
Is there an alternative where you don't deep copy an object and you don't mutate object prop?
You could possibly use v-model. as the docs will say, it's shorthand for the child component having a property bound from the parent and when a change event occurs you emit an update event from the child to the parent to have the parent update the property, and the child will subsequently sync to the new value.
ie:
childComponent *has value change*
onChange (value) => this.$emit("updateValue", value)
parentComponent *recieved "updateValue" event*
onUpdateValue(value) => this.parentValue = value

Vue, separate out component templates

I have got a rather large template at the moment for my component. I want to separate aspects of this into it's own component.
However i'm struggling to pass data to this component. I still want to be able to manipulate the data within the child and have the data in the parent update. So for example if I pass in an object, and then use v-model within the child on a textbox, the changes should reflex within the parent.
So, i'd assume as I loop through the list of objects I would v-model them into my child component, like so:
Main.vue
<card v-for="quote in quotes" v-model="quote"></card>
And then of course accept the input within the new model:
Card.vue
export default {
props: [ 'input' ]
}
However i'm getting the following error and I can't really make sense of it.
You are binding v-model directly to a v-for iteration alias. This will not be able to modify the v-for source array because writing to the alias is like modifying a function local variable. Consider using an array of objects and use v-mode
l on an object property instead.

Vue: Forcing child component to react to changes in its prop (which is a dictionary)

I am currently generating a table which lists problems encountered during the selected test using a component generated with this code:
<tr is="entry" v-for="problem in problems" :key="problem.id" v-bind:foo="problem"></tr>
Each problem corresponds to an item whose relevant information is contained within the problem dictionary and referenced in the first few columns of the table. Since the same item can have multiple problems, the same item can appear in multiple rows of the table. Now, each row features some buttons which allow you to modify the underlying item so as to fix the problems.
Whenever I modify one of those underlying items I need to modify it in all the rows, which i do by calling a function in the parent component, but modifying the data inside of the dictionary does not seem to trigger any of my watches or computes inside of the child component, which currently looks something like this:
Vue.component('entry', {
props: ['foo'],
data: function(){
//does some computations
return data
},
watch:{
foo: function(){
this.recompute_entry()
},
},
methods:{
//various methods, including:
recompute_entry: function(){
//updates the data according to changes brought to the entry
},
},
});
I have attempted to include a different prop which i could bind to an entry in a list in my parent component but, besides being pretty clunky, that didn't end up working either, which makes me think I might've gotten something wrong with my component.
Ultimately, I have relied on the fact that v-for iterates through my list in an orderly fashion, which combined with the fact that I generate no other children in my parent component means that a child component would have the same index in my component's children array as it would in my problems array. Therefore I can use this:
this.$children[problem_index].recompute_entry();
Which kind of feels hack-ish and unreliable, but actually works, for once. Is there no alternative safer method to recalculate my child components based on changes made to their props? I really feel there has to be.
I probably would need to see the exact implementation but it sounds like you need to clone your dictionary to trigger the prop change, ie:
let newProblem = Object.assign({}, this.problem);
// change any nested property
newProblem.some.value = 1
// assign back the cloned and modified dictionary
this.problem = newProblem

List View Item Deleting parameters not passed to Object Data source

I have a ListView bound to an ObjectDataSource, I'm passing some custom parameters to the Insert and Update methods on my bound class methods by adding them to the event.Values map in the ListView ItemInserting/ItemUpdating events.
However when I try to do the same thing on the ItemDeletingEvent the additional parameters do not seem to be passed to the datasource ( If I register a listener for ObjectDataSource.ItemSourceDeleting I only see one parameter, effectively the 'id' of the row).
Is this an expected behavior? I can't see anything in the documentation that indicates as such.
I found a solution -
I Added a 'DeleteParameter' value with the same name as my desired 'custom' parameter to the ObjectDataSource declaration.
Then in the ItemDeleting Event get the ObjectDataSource.DeleteParameters["myparam"] and set the DefaultValue property. Seems like a hack, but it does work.

get all widgets inside an element

From the dojo documents on dijit.registry, I see the forEach method accepts a last parameter thisObject. But it doesn't way what that object is. Is it a dijit widget or a dojo object?
I want to destroy all widgets inside an element (that will be replaced by AJAX) so they can be parsed again without conflicting id's.
dijit.registry.forEach(function(w) {
w.destroyRecursive();
}, dojo.byId("ajaxElement"));
But this destroys ALL widgets on the page...
The thisObject is the scope object to invoke the function passed in as the first parameter of forEach.
A couple of solutions you can use in this case:
1) Use dijit.findWidgets to find all the dijits in a DOM node and destroy them one by one.
dijit.findWidgets returns array of widgets which takes domnode as a parameter
2) dojo.parser.parse returns an array of all the dijits that it creates, store that array and destroy the dijits before you call dijit.parser.parse again.
3) Use dijit.registry.filter to filter out the dijits you want to keep.