I recently started using Vuetify and I am struggling with the class names conflict. the .title is the particular one, because before using Vuetify I already using .title in many places. Simply because the name is too generic. I have found a way to overwrite them but still not ideal because technicatlly you cannot use .title anywhere. It is annoying. I found the style file is from Vuetify's _typography.sacss: file link.
I am wonder if there is a way exlude this file via vue.config.js, or even possible to rename/remove the classes like .title?
Found the solution. Using postcss-prefix-selector. the idea is from https://github.com/vuetifyjs/vuetify/issues/8530
install postcss-prefix-selector
$ npm install postcss-prefix-selector
In vue.config.js
const prefixer = require('postcss-prefix-selector');
module.exports = {
css: {
sourceMap: true,
loaderOptions: {
/* solving the problem Vuetify's built-in style .v-application .title and others causing conflicts
* with existing title classes. */
postcss: {
plugins: [
prefixer({
prefix: '',
transform: function(prefix, selector, prefixedSelector) {
if (selector.startsWith('.v-application')) {
console.log(selector, prefixedSelector);
}
if (selector === '.v-application .title') {
return `.v-application .v-title`;
}
else if (selector === '.v-application .headline') {
return `.v-application .v-headline`;
}
else if (selector === '.v-application .caption') {
return `.v-application .v-caption`;
}
else if (selector === '.v-application .overline') {
return `.v-application .v-overline`;
}
else if (selector === '.v-application p') {
return `.v-application .v-p`;
}
else {
return prefixedSelector;
}
}
})
]
}
},
},
};
Related
PROBLEM
Unavailable variant combinations are different from sold-out because customers don't understand it's the selects which make certain combinations 'not possible'.
Shopify's way of handling this is to display 'Unavailable' in the buy button. But customers think this means sold-out when in reality, they've chosen the wrong combination of variants...
The previous JS workarounds to remove unavailable or 'not possible' variants don't work in Shopify 2.0's new default/flagship theme, Dawn because the JS is different.
As far as I can tell, Dawn's variant JS was recently moved from /asstes/variants.js to line 497 in /assets/global.js.
SKILL
My CSS is decent but my JS is lame, I'm a designer sorry.
QUESTIONS
Based on user interaction with the first variant, how do you hide unavailable variants (not sold-out) in Shopify 2.0 Dawn?
How do you make one variant option set a checkbox instead of a radio button or radio?
What's the best way to add custom text as the first option in selects? e.g. 'Choose a size...' or 'Choose a color...' etc. Is it best to hard-code or use JS for this as well?
RESOURCES/EXAMPLES
Here's a pull request which grabs sold-out from the new Dawn JS but I don't understand how to adapt it for 'Unavailable' sorry (which is a different exception from sold-out): https://github.com/Shopify/dawn/pull/105
Here's an example of how to hide unavailable variants in the older Debut theme which doesn’t seem to work in the newer Dawn JS: https://www.youtube.com/watch?v=vspWDu_POYA
Here's a link to the JS gist referenced in that video: https://gist.github.com/jonathanmoore/c0e0e503aa732bf1c05b7a7be4230c61
And finally, here's the new code from Dawn at line 497 in /assets/global.js
class VariantSelects extends HTMLElement {
constructor() {
super();
this.addEventListener('change', this.onVariantChange);
}
onVariantChange() {
this.updateOptions();
this.updateMasterId();
this.toggleAddButton(true, '', false);
this.updatePickupAvailability();
if (!this.currentVariant) {
this.toggleAddButton(true, '', true);
this.setUnavailable();
} else {
this.updateMedia();
this.updateURL();
this.updateVariantInput();
this.renderProductInfo();
}
}
updateOptions() {
this.options = Array.from(this.querySelectorAll('select'), (select) => select.value);
}
updateMasterId() {
this.currentVariant = this.getVariantData().find((variant) => {
return !variant.options.map((option, index) => {
return this.options[index] === option;
}).includes(false);
});
}
updateMedia() {
if (!this.currentVariant || !this.currentVariant?.featured_media) return;
const newMedia = document.querySelector(
`[data-media-id="${this.dataset.section}-${this.currentVariant.featured_media.id}"]`
);
if (!newMedia) return;
const parent = newMedia.parentElement;
parent.prepend(newMedia);
window.setTimeout(() => { parent.scroll(0, 0) });
}
updateURL() {
if (!this.currentVariant) return;
window.history.replaceState({ }, '', `${this.dataset.url}?variant=${this.currentVariant.id}`);
}
updateVariantInput() {
const productForms = document.querySelectorAll(`#product-form-${this.dataset.section}, #product-form-installment`);
productForms.forEach((productForm) => {
const input = productForm.querySelector('input[name="id"]');
input.value = this.currentVariant.id;
input.dispatchEvent(new Event('change', { bubbles: true }));
});
}
updatePickupAvailability() {
const pickUpAvailability = document.querySelector('pickup-availability');
if (!pickUpAvailability) return;
if (this.currentVariant?.available) {
pickUpAvailability.fetchAvailability(this.currentVariant.id);
} else {
pickUpAvailability.removeAttribute('available');
pickUpAvailability.innerHTML = '';
}
}
renderProductInfo() {
fetch(`${this.dataset.url}?variant=${this.currentVariant.id}§ion_id=${this.dataset.section}`)
.then((response) => response.text())
.then((responseText) => {
const id = `price-${this.dataset.section}`;
const html = new DOMParser().parseFromString(responseText, 'text/html')
const destination = document.getElementById(id);
const source = html.getElementById(id);
if (source && destination) destination.innerHTML = source.innerHTML;
document.getElementById(`price-${this.dataset.section}`)?.classList.remove('visibility-hidden');
this.toggleAddButton(!this.currentVariant.available, window.variantStrings.soldOut);
});
}
toggleAddButton(disable = true, text, modifyClass = true) {
const addButton = document.getElementById(`product-form-${this.dataset.section}`)?.querySelector('[name="add"]');
if (!addButton) return;
if (disable) {
addButton.setAttribute('disabled', true);
if (text) addButton.textContent = text;
} else {
addButton.removeAttribute('disabled');
addButton.textContent = window.variantStrings.addToCart;
}
if (!modifyClass) return;
}
setUnavailable() {
const addButton = document.getElementById(`product-form-${this.dataset.section}`)?.querySelector('[name="add"]');
if (!addButton) return;
addButton.textContent = window.variantStrings.unavailable;
document.getElementById(`price-${this.dataset.section}`)?.classList.add('visibility-hidden');
}
getVariantData() {
this.variantData = this.variantData || JSON.parse(this.querySelector('[type="application/json"]').textContent);
return this.variantData;
}
}
customElements.define('variant-selects', VariantSelects);
class VariantRadios extends VariantSelects {
constructor() {
super();
}
updateOptions() {
const fieldsets = Array.from(this.querySelectorAll('fieldset'));
this.options = fieldsets.map((fieldset) => {
return Array.from(fieldset.querySelectorAll('input')).find((radio) => radio.checked).value;
});
}
}
customElements.define('variant-radios', VariantRadios);
Any help or pointers in the right direction would be much appreciated. Cheers
I need to add a validation on the country field in all place where it can be used.
For registration or address editing it work fine but in checkout I tried several method but nothing worked. I want the validation on the field of the new shipping address form.
I add my validation in an js file countryValidation.js :
Same script for registration or edit address and it work fine
define([
'jquery',
'jquery/ui',
'mage/validation',
'mage/translate',
'domReady!'
], function($){
'use strict';
return function(validator) {
$.validator.addMethod(
"validate-country",
function(value, element) {
if (value === "FR") {
var zipValue = $('input[name="postcode"]').val();
if (zipValue) {
return !(zipValue.startsWith("97") || zipValue.startsWith("98"));
}
}
return true;
},
$.mage.__("You cannot choose France for DOM-TOM Zip Code")
);
return validator;
}
});
I registered it in requirejs-config.js in my module :
var config = {
config: {
mixins: {
'Magento_Ui/js/lib/validation/validator': {
'Gone_Customer/js/countryValidation': true
}
}
}
};
For adding validation to checkout method I tried different method
-> Method A : With a plugin
class AddCountryValidation
{
public function afterProcess(
\Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
array $jsLayout
) {
// Country ID
$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']['children']['country_id']['validation']['validate-country'] = true;
return $jsLayout;
}
}
-> Method B : add validation rule in attribute
In customer_eav_attribute in attribute country_id for validate_rules I added {"validate-country": true}
When I validate the form I have no validation error when I should have one.
Can you tell me if I'm missing something please?
Thank you for your response in the meantime I found something that worked.
I had to do a seperate js validation only for checkout :
define(['mage/translate', "jquery"], function($t, $) {
'use strict';
return function(rules) {
rules['validate-country'] = {
handler: function (value) {
if (value === "FR") {
var zipValue = $('input[name="postcode"]').val();
if (zipValue) {
return !(zipValue.startsWith("97") || zipValue.startsWith("98"));
}
}
return true;
},
message: $t('You cannot choose France for DOM-TOM Zip Code')
};
return rules;
};
});
And in my mixin I change Magento_Ui/js/lib/validation/validator for Magento_Ui/js/lib/validation/rules then my plugin method was working !
Please try this
define([
'jquery',
'jquery/validate'
], function($){
'use strict';
return function(validator) {
validator.addRule(
"validate-country",
function(value) {
if (value === "FR") {
var zipValue = $('input[name="postcode"]').val();
if (zipValue) {
return !(zipValue.startsWith("97") || zipValue.startsWith("98"));
}
}
return false;
},
$.mage.__("You cannot choose France for DOM-TOM Zip Code")
);
return validator;
}
});
I have used return false you can modify according to your need.Tested on version 2.2.2
How to change the size of fields in Infor EAM?
Anyone with experience with Infor EAM would be gladly appreciated.
You could do it using Extensible Framework. For example, following code will change width of work order and equipment description fields if you put it in EF of WSJOBS screen.
Ext.define(
'EAM.custom.external_WSJOBS', {
extend: 'EAM.custom.AbstractExtensibleFramework',
getSelectors: function () {
if( EAM.app.designerMode == false) {
return {
'[extensibleFramework] [tabName=HDR][isTabView=true]': {
afterlayout: function() {
try {
document.getElementsByName( 'description')[0].style.width = '700px';
document.getElementsByName( 'equipmentdesc')[0].style.width = '700px';
return true;
} catch( err) {
return true;
}
}
}
}
}
}
}
);
I'm working on a vue SPA project as front-end and Laravel as my back-end. I realized that on every component methods I keep repeating the same code over and over. I would like more advice on how to make a global class that will handle some of the the Http Exception error messages that have been return from the back-end server with or without customized messages Instead of checking it on every method DRY code.
Here is what I have been doing so far:
catch(error => {
if (error.response.status === 422) {
this.serverValidation.setMessages(error.response.data.errors);
} elseif (error.response.status === 403) {
this.error_403 = error.response.data.errors;
} elseif(error.response.status === 402) {
this.error_402 = error.response.data.errors;
}
....
});
I usually make a js/mixins/Errors.js file with all my error methods and then just include the mixin in my vue files.
export const errorsMixin = {
methods: {
errorClass(item, sm = false) {
return { 'form-control': true, 'form-control-sm': sm, 'is-invalid': this.validationErrors.hasOwnProperty(item) }
},
buttonClass() {
return ['btn', 'btn-primary', this.saving ? 'disabled' : '']
},
handleError(error) {
this.saving = false
if (error.response.status == 422) {
this.validationErrors = error.response.data.errors;
} else {
alert(error.response.data.message)
}
},
}
}
In each vue file:
import { errorsMixin } from '../../mixins/Errors.js'
export default {
mixins: [errorsMixin],
......
.catch((err) => {
this.handleError(err)
})
}
here is my instance
I need to get the login div and hide it using refs
How to achieve this ?
var Text=React.createClass({
componentDidMount:function(){
console.log(this.refs.login.getDOMNode());
},
render:function(){
return (<View ref="login">
<Text>Abc</Text>
<Text>123</Text>
</View>)
}
})`
You could do something like this:
render: function() {
if(this.props.show) {
return (<View ref="login">
<Text>Abc</Text>
<Text>123</Text>
</View>)
} else {
return null;
}
}