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.
Related
I'm writing an app in Vue and I have a really hard time understanding the component hierarchy, namely the parent-child relationships and how to pass data around.
I have a view that contains a map which in turn has some navigation controls and options that are overlayed on top of the map. Now, I want these controls to manipulate the map WITHOUT having to nest the buttons inside the actual maps as it will cause severe display issues (for example, clicking on a zoom button falls through the button and also clicks the next element under it).
My app looks like this:
Mapview
Map
Controls
Options
Optionpanel1
Optionpanel2
...
Now, a HTML input element in Optionpanel1 needs to control something in the Map, which is not actually it's parent component. Also, some data from Map needs to be passed down to Optionpanel1 so it would know what to control. To make matters worse, something in Options also needs to pass something down to Optionpanel1, so, even though event bus would allow communication upwards, it would not solve that I need to pass data from parents to indirect children and also components that are not it's children.
I can actually pass the required property down the line if I nest the Options inside Map and pass it down with :myProp="prop" and then in Options, declare it in props and bind to Optionpanel1, where it is again declared as a prop. But as I mentioned earlier, nesting elements that I do not want to be nested in a visual sense causes massive issues like mouse click falling through. Do elements even need to be nested inside eachother in order to define parent-child relationship?
I would want components to exchange read-only data without Y being a child of X in the DOM. Also, even if nesting components like this would not cause visual issues, does it not seem very annoying to have to register and bind it in every component along the way?
I don't understand why is it so difficult to simply read something from another component. It's starting to seem that Vue is causing a problem that it's supposed to solve? Am I missing something here or am I looking at this in a completely wrong way?
Thanks in advance.
Basically you have 2 options to control complex components:
Handle the actions in your so-called "smart component" (in terms of React), which is the common ancestor for the controlling and controlled components. It's a pretty good solution for small components, but that's not the case.
To separate common logic and data in a Vuex store. I'd recommend you doing this.
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.
I have an external library with TypeScript class instances in observed variable of my app's store:
class Store:
#observable active_obj:ExternalClass;
This instance has a method which, when called, updates its internal state leaving the object as is:
store.active_obj.change()
Now, since Mobx is not observing this object itself nor its (I assume) properties, only changes happening directly on the field active_obj (like new value assigned to it). Since instances of MyClass are provided by external library and ultimately get rendered inside this library's components I can't add observables and observers to its class structure nor React components. Mind you, this is only what I think is the reason that changing the object's properties doesn't trigger re-render...
I had to cheat a bit by using other, observed variable I change directly with nonsense data at the same time I'm calling to unobserved instance for change. Adding references to this variable on components higher up the tree, I can trigger re-render that produces updates on the (unobserving) components of the external library.
My question is, how best to make Mobx aware of change so it can notify observers of store.active_obj instance?
I think this part of Mobx documentation warns about this, but there's no workarounds or solutions for it:
** If likes where objects instead of strings, and if they were rendered by their own Like component, the Likes component would not rerender for changes happening inside a specific like.
from here, at end of the page
Edit
As per #mweststrate's question, I provide some context:
My app controls its data, but it has to create external class' instances from that
Instance's data is encapsulated and mutated in place, but it's done by asking from my app's side through user triggered events (meaning, I know when data is updated)
Basically class uses app's data to provide different views into data based on user selection and renders it with its React components
I also use this changed data elsewhere in the app in components I control
Changed data is part of external class' internals and I can't depend on it
Since Mobx tracks mutations it can see, using Observable doesn't directly work
Some possible solutions I thought:
manually notify observers that observable active_object has changed when I have called the instance it references to change
have a container object that Mobx can track and when I change its sentinel property, that update is noticed and actual instance with it
I am trying to create fully reusable component using Vue.js 2 and single file components, and right now my approach seems to be impossible to realize.
The goal is to create component for creating forms for a complex, nested JSON structure. This structure is supposed to be edited and then sent to the server. The component itself displays a header and submit button but the fields along with their placing is entirely the responsibility of the user of my component. (front-end engineer)
The MyForm component (implementation is not relevant here) is passed the JSON data and url to post them to.
The form is supposed to be reusable by many other users and the contents of the form itself is supposed to be not relevant. It may have a mix of html/inputs/custom components as children.
Let's imagine a simple scenario without data nesting with the following data:
var mymodel={ name : "My name", surname : "My surname" }
And a form i would like to create using my component:
<MyForm :model="mymodel" :url="http://localhost/post">
<div>
<MyTextInput v-model="model.name" label="Name"/>
<MyPanel>
<MyTextInput v-model="model.surname" label="Surname"/>
</MyPanel>
</div>
</MyForm>
Therefore:
MyForm gets passed a model to submit, stores it in data
MyTextInput is a custom component for displaying input with label
Second MyTextInput is the same component but created in another component contained called 'MyPanel' since this field needs to be placed differently.
As we can see there are many problems with passing variables and composition itself:
Composition:
If i put a <slot></slot> in the tempplate of MyForm for displaying the fields it would be compiled in parent scope, therefore all children (including MyTextField) would not have access to the "model"
If i try to use <MyForm inline-template> i cannot automatically display the form header and footer since all content is being replaced. Additionally when using single file components the compiler will look for all components inside the inline-template which means that i would have to import MyTextInput and MyPanel into MyForm which is not practical. I do not know in advance all components that will never end up in my form!
Passing variables:
If i use the variables directly from "model" (in first TextInput) i receive warning that i am modifying a variable from parent and it will be overwritten on next render (but in this case it will not be overwritten since i am INTENTIONALLY modifying the parent)
I cannot pass the model into second MyTextInput without passing it to MyPanel first. Actually i would have to pass it into EVERY custom component in between. And i do not know in advance how many custom components will there be. Which means that i would have to modify the code of every component that would ever be put into MyForm and require users to pass the data for each custom component they include.
If i would try to properly inform the parent about changes i would need to add v-on: event to every textinput and every custom component in between in order for the event to reach MyForm.
As i have said the component was supposed to be simple and easilly reusable. Requiring users of this component to modify code of every child they put into it and requiring them to add v-on: to every component inside does not seem practical.
Is my idea solvable using Vue.js 2.0 ? I have designed the same component before for AngularJS (1.5) and it was working fine and did not require to add modifications to each child of the form.
I've been using a ui framework based on vue 2.0 and you may get some ideas from its implementation. Based on its implementaion and my little experience with it, I think it's the person who uses your framework's responsibility to assemble the form-model. Also, for a form, we can always easily get all the data to be sent by using fields' value props without v-model's help.
The framework's doc on form element may also be helpful but it's currently only available in Chinese except for the code samples.
I suggest you to use Form Input Components using Custom Events to pass variables in your form.
Mutating a prop locally is now considered an anti-pattern, e.g.
declaring a prop a and then set this.a = someOtherValue in the
component. Due to the new rendering mechanism, whenever the parent
component re-renders, the child component's local changes will be
overwritten. In general, in 2.0 you should treat props as immutable.
Most use cases of mutating a prop can be replaced by either a data
property or a computed property.
Those are three concepts on Yii that I really don't get what should we use, on what scenarios?
Can anyone be kind enough to clarify those Yii elements, and on what situation should we use them?
In documentation of CForm one can read the following:
...we can divide a form
in two parts: those that specify each individual form inputs, and
those that decorate the form inputs. A CForm object represents the former part...
...and CActiveForm represents the latter.
In other words, CForm specifies elements of the form but CActiveForm (being a widget) renders it.
Looking at the source code we state that CForm can also render() itself and its rendering relies on and is wrapped by CActiveForm widget by introducing its configuration property activeForm, though rendering input elements and buttons is implemented by its own methods renderElements() and renderButtons() relatively. By default their implementations rely on classes using CHtml's static methods what is exactly the same (or almost exactly the same) what CActiveForm's rendering methods do. Of course, default behavior can be overriden by extending the class.
That's why it's the question of a taste which technique to use: CActiveForm widget alone combining form fields' and buttons' declaration with their representation in a view file by calling convenient (required) methods of CActiveForm instance or CForm class declaring form's input specifications in a separate configuration file and customizing its rendering by pointing at appropriate active form widget and/or by overriding default rendering methods. The latter technique allows to reuse a form in several actions easily and is no more than using form builder.
Check here for live examples of ActiveForm, CForm, et cetera. You can also see the live Model, View & Controller files.