Views: 229
Last Modified: 28.04.2022

  About mutations

Option to mutate (customize) was created to allow modifying standard component behavior without changing a source code.

Any standard definition object parameter can be subjected to mutation. Such object was used when registering a component or added later by another mutation. Mutation must have only those parameters that you want to edit or add. The rest of parameters will remain unchanged.

You can register mutation before and after registering a mutable component.

Note: In contrast to BitrixVue 2, component mutation in BitrixVue 3 no longer applies to clones of original component.

Mutations are created primarily for mutable components, but you can use them for classic Vue components as well cloning them; learn more in the article Component cloning.

For example, you need to replace the method sendText in the original component. Then the object mutations will look as follows:

{
	methods:
	{
		sendText()
		{
			...
		}
	}	
}	

After applying this mutation, the remaining functions will remain unchanged. Adding new method is done in the same manner as is the replacement of existing method. Mutation rules apply to all fields of parameter object, such as methods, props, template and etc.

  String values mutation

Sting values can be replaced with option of using the previous text. For this, you need to indicate the name for this parameter, enclosed with hashtag symbols in the new text. For example, new component template can use the original template. For this, add the tag #PARENT_TEMPLATE# to the template.

For example, original template looked as follows:

{
	template: "<span>Hello</span>"
}	

Now, use the old template in your new template:

{
	template: "<div>#PARENT_TEMPLATE#, world!</div>"
}

Final layout after component rendering will look as follows:

<div><span>Hello</span>, world!</div>

  Object mutation

Objects (such as props, methods, computed, components) can be expanded or replaced by new values.

Additionally, replacing existing parameters in objects allows accessing previous value. Add the parent to the key name and enter the first letter in the uppercase. For example, original component has a calculated property dateText. In a mutation, we can query its name using parentDateText.

Let's review the example of method replacement in case of sendText that sends an event with text to the above component:

{
	methods:
	{
		sendText(text)
		{
			this.emit('send', text);
		}
	}	
}	

You are satisfied with method operation, but you want to modify the text before sending:

{
	methods:
	{
		sendText(text)
		{
			// edit the text
			text = '['+text+']';
			
			// call parent method, but now with another text version
			this.parentSendText(text);
		}
	}	
}		

Let's overview another example of calculated property with a localization example.

Here's a calculated property that generates localizations in original component:

{
	computed:
	{
		localize()
		{
			return BitrixVue.getFilteredPhrases(this, 'IM_MESSENGER_MESSAGE_');
		},
	},
}		

You can add you own phrases without loosing original ones:

{
	computed:
	{
		localize()
		{
			return Object.assign({},
				this.parentLocalize,
				BitrixVue.getFilteredPhrases(this, 'IMOL_MESSAGE_')
			);
		},
	},
}			

  Mutation of properties: props and watch

The props property cam be presented by both an object and an array. In case original and mutation don't match, the property will be converted to object. In all the rest, the mutation algorithm repeats the general object mutation procedure.

The watch property is a little different from the standard object mutation. It can still use the previous function value, but prefix won't a parent, but parentWatch (its done to avoid mutation errors, when you need to simultaneously edit both calculated property and watcher).

Original component:

watch: {
	counter(current, previous)
	{
		if (current === 5)
		{
			this.watcherText = `Watcher detects change counter ${current}`
		}
	},
},		

You have applied the mutation:

watch: {
	counter(current, previous)
	{
		this.parentWatchCounter(current, previous);
		if (current === 10)
		{
			this.watcherText = `Watcher detects change counter ${current}`
		}
	},
},	

During operation of the component, the updated counter triggers text updates twice: once at value 5, second time at value 10.

  Function mutation

Functions (such as data(), created()) will be replaced with new ones, but you can use them as original versions via prefix parent.

The function data() in the original component:

{
	data()
	{
		return {
			data1: 'text1',
			data2: 'text2',
        }
	}	
}	

The method data(), indicated in the mutation:

{
	data()
	{
		return {
			...this.parentData(),
			data2: 'mutated data2',
			data3: 'text3',
        }
	}	
}		

Component operational time result:

{
	data1: 'text1',
	data2: 'mutated data2',
	data3: 'text3',
}	

  Mutation with full replacement

Sometimes, you have to not only modify elements or update current properties, but to completely replace them. You need to indicate the prefix replace to do it, and capitalize the property itself name.

Such approach is supported by the following properties: mixins, inject, emits.

Example:

{
	replaceMixins: [
		textarea
	]
}	

  Example of complex mutation

Let's present the component that prints values from 1 to 10 as a black text. We will mutate and clone it.

First mutation will change the component in such a way, that it will print the event numbers in red color and uneven numbers - in green color.

Second mutation will add a frame around the template and expand its numerals to 15.

Create second component based on the first one using the cloning, but update it to show numerals in random order.

Important! The clone will be created using the original component (despite to previously applied mutations).

import {BitrixVue} from 'ui.vue3';

const Digits = BitrixVue.mutableComponent('ui-digits', {
	data()
	{
		return {
			digits: [1,2,3,4,5,6,7,8,9,10]
		}
	},
	computed: {
		digitsList() {
			return this.digits;
		}
	},
	template: `
        <span v-for="digit in digitsList" style="padding: 0 5px;">{{digit}}</span>
    `
});

BitrixVue.mutateComponent(Digits, {
	computed: {
		digitsList()
		{
			return [
				...this.parentDigitsList,
				11, 12, 13, 14, 15
			];
		}
	},
	template: `
        <template v-for="digit in digitsList">
            <span v-if="digit % 2" style="color: green; padding: 0 5px;">{{digit}}</span>
            <span v-else style="color: red; padding: 0 5px;">{{digit}}</span>
        </template>
    `
});

BitrixVue.mutateComponent('ui-digits', {
	template: `
        <div style="border: 1px solid red; display: inline-block;">
            #PARENT_TEMPLATE#
        </div>
    `
});




const DigitsRandom = BitrixVue.cloneComponent(Digits, {
	computed:
    {
        digitsList()
        {
            return this.shuffleArray(this.digits)
        }
    },
	methods:
    {
        shuffleArray(array)
        {
            for (let i = array.length - 1; i > 0; i--)
            {
                const j = Math.floor(Math.random() * (i + 1));
                [array[i], array[j]] = [array[j], array[i]];
            }
            return array;
        }
    },
});



BitrixVue.createApp({
	components: {
		Digits,
		DigitsRandom
	},
	template: `
        <div><strong>Mutated component - colors and numerals</strong></div>
        <Digits/>

        <div><strong>Cloned component - random order</strong></div>
        <DigitsRandom/>
    `
}).mount('#application');	





Courses developed by Bitrix24