Vue js custom select - binding to the - data-binding

I have a custom select box.
<select-box :options="['Male', 'Female', ]"
title="Gender"
v-bind:value="selected"
v-model="person.gender"
>
</select-box>
The .vue code
<script>
export default {
props:['title', 'options'],
data () {
return {
selected: this.title,
dropdownVisible: false,
}
},
methods: {
toggleOptions() {
this.dropdownVisible = !this.dropdownVisible
},
selectValue(option) {
this.selected = option;
this.toggleOptions();
}
}
}
How can I bind the selected value directly to the model (person.gender)?

I assume that above .vue code belongs to select-box component.
Because I saw you use v-model, to bind value directly to v-model, you need to $emit inside children component.
You can change your selectValue function
selectValue(option) {
this.selected = option;
this.$emit('input', option);
this.toggleOptions();
}

Related

How to change the Gutenberg Group Block's "Inner blocks use content width" Toggle to Off/False as Default

When you wrap a new set of blocks in the core/group block the "Inner blocks use content width" toggle switch defaults to true. There is an object attribute showing called layout for that block. I'm assuming that I can update the settings on the layout attribute like I can with the align attribute.
Here is how I'm updating the align attribute:
const { addFilter } = wp.hooks;
const { assign, merge } = lodash;
function filterCoverBlockAlignments(settings, name) {
if (name === 'core/group') {
return assign({}, settings, {
attributes: assign( {}, settings.attributes, { align: {
type: 'string', default: 'wide'
} } ),
});
// console.log({ settings, name });
}
return settings;
}
addFilter(
'blocks.registerBlockType',
'intro-to-filters/cover-block/alignment-settings',
filterCoverBlockAlignments,
);
The above works so I assume updating the layout's default would be similar, but either I don't have the syntax for an object type correct, or possibly you can't update the layout object like you can update the align string. This is what I tried for the function:
function filterCoverBlockAlignments(settings, name) {
if (name === 'core/group') {
return assign({}, settings, {
attributes: assign( {}, settings.attributes, { layout: {
type: 'object', [{
type: 'default'
}]
} } ),
});
// console.log({ settings, name });
}
return settings;
}
In short I'm trying to get the blocks layer attribute (which is an object and not a string) have it's attribute of type to default to "default" instead of "constrain".
I mean yes, you could solve it by filtering. What I would suggest however, is making a block-variation. Then setting that block-variation as the default. That block variation then can have any of your settings you like to set. Quite simple in theory.
By default, all variations will show up in the Inserter in addition to the regular block type item. However, setting the isDefault flag for any of the variations listed will override the regular block type in the Inserter.
source: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/
wp.blocks.registerBlockVariation( 'core/group', {
name: 'custom-group',
// this one is important, so you don't end up with an extra block
isDefault: true,
// and here you add all your attributes
attributes: { providerNameSlug: 'custom' },
} );
Here is a slightly cleaner variant (using destructuring), if you have more code:
// extract the function from wp.blocks into a variable
const { registerBlockVariation } = wp.blocks;
// register like above
registerBlockVariation();

Detect change to modelValue in Vue 3

Is there a way to detect change to modelValue in a custom component? I want to push the change to a wysiwyg editor.
I tried watching modelValue but emitting update for modelValue triggered that watch, which created circular data flow.
Code:
export default {
props: ['modelValue'],
watch: {
modelValue (val) {
this.editor.editor.loadHTML(val)
}
},
mounted () {
this.editor.editor.loadHTML(val)
this.editor.addEventListener('trix-change',
(event) => this.$emit('update:modelValue', event.target.value))
}
}
<TextEditor v-model="someHtml"></TextEditor>
In VueJS v3, the event name for custom v-model handling changed to 'update:modelValue'.
You can listen to these events like this: v-on:update:modelValue="handler"
For a more complete example, lets assume you have a Toggle component with these properties/methods:
...
props: {
modelValue: Boolean,
},
data() {
return {
toggleState: false,
};
},
methods: {
toggle() {
this.toggleState = !this.toggleState;
this.$emit('update:modelValue', this.toggleState);
}
}
...
You can use that Toggle component:
<Toggle v-model="someProperty" v-on:update:modelValue="myMethodForTheEvent"/>
As a side note, you could also v-model on a computed property with a setter; allowing you to internalise your state changes without using the update:modelValue event. In this example, it assumes you v-model="customProperty" on your custom Toggle component.
computed: {
customProperty: {
get() {
return this.internalProperty;
},
set(v) {
this.internalProperty = v;
console.log("This runs when the custom component 'updates' the v-model value.");
},
}
},
I had the same problem and solved it using a slight tweak to the way you call the watch function:
setup(props) {
watch(() => props.modelValue, (newValue) => {
// do something
})
}
Hence, the important thing is to add () => props.modelValue instead of just putting props.modelValue as the first argument of the watch function.
try that:
watch: {
...
modelValue: function(val) {
console.log('!!! model value changed ', val);
},
...

How to update widget when new style is applied

I'm making an extension with a list containing a checkbox with a text item (St.label) that change style when toggled.
I'm listening to the toggle event, and as the item is toggled, I set a new style for my text using set_style_class_name() on a my Stlabel. But the style of the object don't change. The only solution that I have found is to destroy and remake all the item of the list and set a different class in the init of the object.
How could I just update the item that have been checked ?
Here the item that I'm using, I put a listener on the checkbox that trigger the toggle() function, in this function I'm updating the class, which should remove the 'text-checked' class and so the text should't have 'text-decoration:line-through' property.
const PopupMenu = imports.ui.popupMenu;
const Lang = imports.lang;
const { Atk, Clutter, St, GObject } = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const CheckboxLib = Me.imports.src.checkbox;
var PopupCheckBoxMenuItem = GObject.registerClass({
Signals: {
'toggled': { param_types: [GObject.TYPE_BOOLEAN] },
'deleted': { param_types: [GObject.TYPE_BOOLEAN] }
},
}, class PopupCheckBoxMenuItem extends PopupMenu.PopupBaseMenuItem {
_init(text, active, params) {
super._init(params);
this.label = new St.Label({
text: text,
y_align:Clutter.ActorAlign.CENTER,
x_expand: true,
style_class: active ? "text-checked" : ""
});
this.tags = new St.Label({
text: "API",
y_align:Clutter.ActorAlign.CENTER,
style_class: "tag-item"
});
this.icon = new St.Button({
style_class: 'remove-task',
can_focus: true,
});
this.icon.connect('clicked', Lang.bind(this,function(){
this.emit('deleted', this._checkbox.state);
}));
this.icon.add_actor(new St.Icon({
icon_name: 'window-close-symbolic',
style_class: 'icon-remove-task'
}));
this._checkbox = new CheckboxLib.CheckBox(active);
this._checkbox.connect('clicked', Lang.bind(this,function(){
this.toggle();
}));
this.accessible_role = Atk.Role.CHECK_MENU_ITEM;
this.checkAccessibleState();
this._statusBin = new St.Bin({
x_align: Clutter.ActorAlign.START,
x_expand: false,
});
this.add_child(this._statusBin);
this.label_actor = this.label;
this.add_child(this.tags);
this.add_child(this.label);
this.add_child(this.icon);
this._statusLabel = new St.Label({
text: '',
style_class: 'popup-status-menu-item',
});
this._statusBin.child = this._checkbox;
}
setStatus(text) {
if (text != null) {
this._statusLabel.text = text;
this._statusBin.child = this._statusLabel;
this.reactive = false;
this.accessible_role = Atk.Role.MENU_ITEM;
} else {
this._statusBin.child = this._checkbox;
this.reactive = true;
this.accessible_role = Atk.Role.CHECK_MENU_ITEM;
}
this.checkAccessibleState();
}
activate(event) {
super.activate(event);
}
toggle() {
this._checkbox.toggle();
this.emit('toggled', this._checkbox.state);
//Updating class
this.label.set_style_class_name("new_class");
this.label.real_style_changed();
this.checkAccessibleState();
}
get state() {
return this._checkbox.state;
}
get delete_icon() {
return this.icon;
}
setToggleState(state) {
this._checkbox.state = state;
this.checkAccessibleState();
}
checkAccessibleState() {
switch (this.accessible_role) {
case Atk.Role.CHECK_MENU_ITEM:
if (this._checkbox.state)
this.add_accessible_state(Atk.StateType.CHECKED);
else
this.remove_accessible_state(Atk.StateType.CHECKED);
break;
default:
this.remove_accessible_state(Atk.StateType.CHECKED);
}
}
});
The problem was the property I changed in the css class.
For an unknown reason, style change doesn't seem to redraw when I set a class with only text-decoration property but if I add a change in the color, even if it is the same color it does work even without St.Widget.style_changed().
So if I do this.label.set_style_class_name("text-checked"); to change my class, the change doesn't work if my css class is as follow :
.text-checked
{
text-decoration: line-through !important;
}
But this work :
.text-checked
{
text-decoration: line-through !important;
color: black;
}
Must be an issue with how the style change event work for Gjs component.
Issue open here : https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2811
The most direct seems to be St.Widget.style_changed(). This seems to forcibly mark the style state as dirty and trigger a redraw (St.Label is a subclass, so just call myLabel.style_changed()).
The proper route is probably St.Widget.ensure_style(), though.
I didn't look too deep, but the issue may be that widgets aren't being marked as having their style changed or maybe the change isn't being propagated to children or something.

How to update text element after property change in Polymer 3?

So I'm using a data table which has an active element. When that active elment changes I store the name of the active element in a property of my polymer element. Then I display this String property in a div.
Now I know for certain that the property change works, because I console.log it after a change, the div displaying the property doesn't update and continually displays the default value I have set.
export class ProjectsOverview extends PolymerElement {
static get template() {
return html`
...
<div>{{currentProject}}</div>
...
`
}
static get properties() {
return {
currentProject: {
type: String,
value: "placeholder",
notify: true,
reflectToAttribute: true
}
};
}
connectedCallback() {
super.connectedCallback();
const grid = this.shadowRoot.querySelector('vaadin-grid');
grid.addEventListener('active-item-changed', function(event) {
const item = event.detail.value;
grid.selectedItems = [item];
if (item) {
this.set('currentProject', item.name);
} else {
this.set('currentProject', '');
}
console.log(this.currentProject);
});
}
}
My expected result would be that every time the currentProject property is updated, the div displaying the property updates as well.
The active-item-changed callback does not have its context bound to the Polymer instance (i.e., this is the grid and not the Polymer component). Instead of the function expression, use an arrow function to automatically bind this to the correct context.
// grid.addEventListener('active-item-changed', function(event) { // DON'T DO THIS
grid.addEventListener('active-item-changed', (event) => {
/* this is the Polymer instance here */
this.set('currentProject', ...);
})
Your scope is wrong. You're using an anonymous function so when you try to set currentProject, you do that when your this is your anonymous function. Use .bind(this) to fix your problem.
grid.addEventListener('active-item-changed', function(event) {
const item = event.detail.value;
grid.selectedItems = [item];
if (item) {
this.set('currentProject', item.name);
} else {
this.set('currentProject', '');
}
console.log(this.currentProject);
}.bind(this));

Vue with binded aria-hidden

I want to show a modal with vue.
with aria-hidden="false" it should be visible.
I added this snippet with a v-bind :aria-hidden="modalHidden" to the div and set it to false by default (for testing purpose only):
created() {
this.modalHidden = false;
},
but this attribute is only in the DOM when it's != false.
is there any possibility to set this value to false?
You must use data to change bind value. For example:
:aria-hidden="[!isVisible]"
data() {
return {
isVisible: false
};
}
After that you can change value at any stage of the component:
// mounted
mounted() {
this.isVisible = true
},
// or event
methods: {
onClickEvent() {
this.isVisible = !this.isVisible
}
}
I hope this will help you.

Resources