I'm trying to create a reusable components with BEM methodology in mind by using global mixins.
Here is a live example of what I'm trying to do in this example https://codesandbox.io/s/ojyym18355
As you can see, I would like to be able to pass multiple props as an array with class, so it will render test test--one, so far only the last class test--one is output.
Any idea how I can solve this problem? thank you!
In your code example, when you add multiple bindings this way v-bind="[test, test_one]", it transforms into following bindings on the element:
class="test"
class="test--one"
Which, means that the last value overwrites class binding and you are left with a single value of test--one.
As a solution, classes can be passed the same way as multiple bindings - as an array or object. Here is an example:
Note, that this is an example of more flexible usage of bindings. In order to make reusing components efficiently, initial data format of mixin's data property may require adjustments.
Related
After trying to find solution to this issue for hours on various forums i am posting this here.
So i have two components. 1) App and 2) Todo. Both renderes a list and i can complete items so there will be two lists one for incomplete items and one for complete items. you can click on item and it will be gone to complete items list.
So in my example you can see i am using same component but with two diffreent ways to give data to component. one using API and one using native js Data. in both cases it renderes but with api i can click on list item and it will be gone to completed list but with javascript array example it doesn't work. i am completely amazed with this because component is same. how it can affect like that.
many answer here do tell me that computed properties are not reactive as they are cached but what’s the solution to that ? i can put data variable but then the first case of api will not work because time it takes to fetch it. so please help me with this one.
complete code at sfc playground
You have reactivity issues the computed property probably expects that value to be constant because you provide a non-reactive array from the parent.
I think you have 2 options here:
you either provide a reactive prop from parent
or you set a local data attribute in the child-component so that vue will know that it can change
Your fiddle didn't work for me so I copied your code to codesandbox, I have both examples there but commented out the first solution, there you basically simply add the array to the data object and reference that in the code.
Second solution you can add a mounted hook to define reactiveAssignments to your data in the child component this way it will have the same reference so that's why it would work that way.
I think the first solution is simpler, but it is really up to which one you prefer.
You can check the solutions here in my codesanbox
A better approach could be though by setting up component events instead of v-models in the child you should use it in the parent because this way you are directly modifying the props. You can read more about this here: https://vuejs.org/guide/components/events.html#usage-with-v-model
I have this weird bug with a slot that is unreliable in certain unknown cases.
Components
There are 3 hierarchical components.
The grandchild (headlessTable), which offers a slot named arrayValue.
The child (collapsableCard), which passes the slot between grandchild and parent.
The parent (orderDataCard), who decides to render a link for that slot.
Problem: Instead of rendering the link of the parent, the default slot html of the child is being rendered when new data is loaded.
Datastructure (orderDetails)
process (obj)
mark (string)
common (obj)
additionalArguments (array)
category (string)
type (string)
name (string)
value (string)
salesOrganisation (obj)
invoices (array)
invoiceAgreementId (string)
paymentType (string)
Reproduction
Stackblitz or Codesandbox
Please look at the field additionalArguments, it contains a link.
Press ALT+M to simulate fetching new data. Now, instead of rendering a link, the default slot html for that named slot is rendered instead.
You can press ALT+J to load the original data, but this time there's no link.
Initial data (ALT+J)
Loaded data (ALT+M)
Type
Equal value
mark
str
false
common
common
obj
true
salesOrganisation
salesOrganisation
obj
true
invoices (empty)
invoices
arr
false
How 2 resolve
if you uncomment line 68 in app.js (or line 73 in App.vue if you're on codesandbox), which is the field called mark
if invoices is not initially empty in app.js
if mark is removed from html in orderDataCard
if salesOrganisation is removed from html in orderDataCard
if the html in the v-for template section for invoiceItems is empty in orderDataCard
Obviously, these are not solutions.
Notes
In any case, there is no dependence or anything between any of the fields, so it's hard for me to understand why this happens and I suspect this to be a bug with vue. I already created an issue for this. However, devs won't look at the reproduction, because they think it's not minimal as #lines > 100. As soon as I delete any more meaningful lines, the bug is resolved and the removed code is not faulty, so it's very frustrating to work on this. I could still remove lines that are not meaningful, but that would make it more difficult for everyone involved to understand what data is being rendered.
Is anyone able to acknowledge the fact that this is a problem with vue and that the code is not reducible OR (I would prefer this) is anyone able to fix this?
The problem is linked to Vue handling of multiple instances of the same component. In OrderDataCard.vue you have two instances of Collapsable-Card without unique keys. In this case:
Vue uses an algorithm that minimizes element movement and tries to
patch/reuse elements of the same type in-place as much as possible.
I don't quite know how these algorithms work, and why, apparently, it reused the second instance (without a defined slot content), but, setting a unique key for these components solved the issue.
See the working code sandbox: https://codesandbox.io/s/admiring-hamilton-5ytpp?file=/src/components/OrderDataCard.vue:133-149.
Note: I couldn't trigger keyboard events in my browser, so I triggered them on button click.
This may not be the solution, but could help find it:
Objects
I noticed you are working with objects and turning them into arrays. Objects properties can be problematic to work with, because unlike arrays updated properties are not propagated. This is a problem with JavaScript, not Vue. Vue was only possible because of observers introduced, but objects are still not part of that.
You might run into problems when an object is partially updated.
I would suggest looking at Vue.set.
Old code of mine invokes it explicitly by window.Vue.set() for changes in object properties so Vue can propagate them correctly.
That is kind of a bug in Vue, but again stems from JavaScript itself.
Computed arrays
I'm not entirely sure but the computed arrays don't save the above issue with working with objects.
I would go the safe route and use Vue.set() when updating objects and object properties. You can still use the computed arrays then.
Otherwise the obvious: Make real arrays out of the objects instead of working with objects half the time.
this.process
Is there a good reason you are using this.process explicitly instead of the component's props? Or is that a component from a library?
Slots
Have you tried the exact same code but without using the collapsable-card? Just output the link itself? It might point to slot problems in the collapsable-card component. Maybe also partially because of the objects thing from above.
I am trying to model a part of my VUE app with UML. I used a class diagram to show the structure and a sequence diagram to show one specific behavior.
There are some things I am not sure about:
in regards to the class diagram: the Form copmonent imports the data criteria, whos criterium is passed to the child and the option to the grand-child. So each instance of the child FormItem holds one criterium of criteria and each instance of the grandchild BaseRadio holds one option of the options array. So the data flow is through the parent. Can I still relate criterium - FormItem and option - BaseRadio as indicated by the blue composition arrows?
in regards to the sequence diagram, my aim is to visualize the cross-component data flow and custom event communication with emitting events and passing props. I sketched these as synchronous messages, since they don't return anything but this feels weird?
are the functions called within one component supposed to be reflexive messages? (as shown in the sequence diagram for setoption(option):void for example). And I guess the presentation of computed properties integrationChance and integrationProspectPercentage as reflexive message is wrong, since they dont represent functions?
Here, the draft of the UML class-diagram sketching the VUE app:
And the sequence diagram:
And here the description of what this app does:
The data for the function is imported as a JSON Object criteria.
For each criterium (e.g. gender, age, etc.) criteria holds an object named criterium, which has a label and an array options. The options array holds an option for each attribute (male, female, etc.).
Each option has a name (e.g. male) and a correspondent value (e.g. 0).
The Form component imports the criteria object and two other components: FormItem and FormResultBar. The Form holds only one FormResultBar. For each criterium in criteria the form holds one FormItem and for each option the FormItem holds one BaseRadio button.
When the user clicks on a BaseRadio button, its computed property selectedValue emits an event to the FormItem, passing the value of the option that was clicked and the correspondent criteriumKey.
The FormItem component then sets the selected option (setOption()) and saves it (saveOption(option, criteriumKey) by emitting an event to the parent component Form and passing the parameters option and criteriumKey. In the Form component the saveOption(option, criteriumKey) saves the selected Option by storing it in the selections Object.
The selections Object holds all the selected options for each criterium. The computed property integrationChance in Form item then calculcates the integrationChance by adding all the values of the options stored in selections. The method integrationChancePercentage transform the logisitic regression value into percentages. The integrationChancePercentage is then passed as the prop “result” to the FormResultBar, where the result gets displayed.
You can find the implemented part of the application here.
The key question here is not whether UML is suitable for the job or not, but what do you want to show in your diagrams:
In this other question I have developed what relevant diagrams could be used for in a JS context with Electron. I think it may answer your question about which diagrams to use.
You have opted for a class diagram. It explains well the the internal structure based on classes and their relationships:
A Vue component can be represented by a class:
Components are reusable Vue instances with a name (source: Vue guide)
props may be shown it as an UML property:
Props are custom attributes you can register on a component. When a value is passed to a prop attribute, it becomes a property on that component instance. (source: Vue guide)
UML classes are usually represented with a box with 2 separators. The first part is the class name, the second part is for the properties and a third part are for operations. Since props can be accessed from other components, it seems better to give them a public accessibility in the class diagram (+ instead of -)
Computed properties could be shown as derived properties, i.e. with its name preceded by /:
(...) its value or values may be computed from other information. Actions involving a derived Property behave the same as for a nonderived Property. Derived Properties are often specified to be read-only (i.e., clients may not directly change values). But where a derived Property is changeable, an implementation is expected to make appropriate changes to the model in order for all the constraints to be met, in particular the derivation constraint for the derived Property. (source: UML specifications)
Your “methods” are operations in UML,.
I’m not a Vue expert, but I understand that “watchers” seem to be some special kind of methods.
More generally, I'd suggest to use a custom UML profile for Vue. It may define stereotypes for each of these kind of elements (e.g. «Vue component», «props», «computed») that would precede the name of the element or be above it. This could convey a more precise semantic, especially if there could be ambiguities (e.g. methods vs watchers).
Your narrative explains the interaction between components. This is best documented with a sequence diagram. Lifelines would be instances of components or props instances of a component, and messages exchanged between lifelines would correspond to Vue methods, and other means to exchange information.
I have a component library where i would like to standardize the props, component etc.
Thoughts on combining them props/methods/other mixins/etx into one larger mixin
All property names would be the same
Remove duplicated code on refactoring to adjust components from local props/methods/computed/ to "global"
Not all components would have need for every piece of data contained within the mixin - point 4
Would tree shaking remove the unused code on Rollup?
Is this a good idea?
If your component library is not constrained to using Vue 2 you might want to take a look at Vue Composition API to share functionality (methods + reactive state) between different components.
Mixins might not be what you really want to be using because you kind of lose information as to what features/props/methods really will be put inside your component without re-checking the mixin code. You also might run into issues when component options get merged by Vue at runtime. Check out these posts for more information:
https://css-tricks.com/how-the-vue-composition-api-replaces-vue-mixins/
https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html
As for sharing props: What I've seen just yesterday (but not yet tried!) in a talk by John Leider - creator of Vuetify - is create a function that returns the props you want to reuse between components. Then you just call said function inside your props definition and use the spread operator.
I have a VueX state that contains a list of items. E.g.:
{
operations: Operation[]
}
We need to display each Operation as an item in a list. So we have an OperationList component and an OperationItem component.
When it comes to rendering the list (v-for), would it be recommended to pass the entire item as a prop or just the id and have the OperationItem read the data from VueX?
Basically:
<operation-item v-for="operationId in operationIds" :id="operationId" :key="operationId"/>
vs
<operation-item v-for="operation in operations" :operation="operation" :key="operation.id"/>
I think it might be a preference choice but in my projects I usually pass all the prop of the components that way :
<operation-item
v-for="operation in operations"
:key="operation.id"
:prop1="operation.prop1"
:prop2="operation.prop2"
:prop3="operation.prop3"
/>
I'm not sure if that's a good practice or not but in this case, it's more flexible, you don't need to give a structured object for it to render, you just have to give it all it's properties.
A bit like for a class constructor, I would pass all the necessary parameters separately instead of passing them in an $option array or Settings class.
For some components, it also doesn't make sense for them to be aware of the store, they should juste be "stupid" rendered components.
I hope it's clear enough that you get my point !
I'd say pass the entire item. That way your component doesn't need to know where the data came from and you would be able to reuse the component in situations where the data didn't come from Vuex.