Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using CustomPhoneNumberPrefixWidget(MultiWidget) passing css class in attrs #341

Closed
cusco opened this issue Oct 23, 2019 · 2 comments
Closed

Comments

@cusco
Copy link

cusco commented Oct 23, 2019

Hello. I would like the select with country options, and the input field with phone number to have a specific css class.

Overriding the CustomPhoneNumberPrefixWidget class, it should be possible to set:
widgets = (PhonePrefixSelect(initial, attrs={'class': 'prefix_select'}), TextInput(attrs={'class': 'phone_input'}))

However this was not working.

I ended up overriding def get_context and class PhonePrefixSelect as follows.

Would it be possible to fix it in the upstream?
Thanks

class CustomPhoneNumberPrefixWidget(MultiWidget):
    """
    A Widget that splits phone number input into:
    - a country select box for phone prefix
    - an input for local phone number
    """

    def __init__(self, initial=None):
        widgets = (PhonePrefixSelect(initial, attrs={'class': 'prefix_select'}), TextInput(attrs={'class': 'phone_input'}))
        super().__init__(widgets)

    def decompress(self, value):
        if value:
            if type(value) == PhoneNumber:
                if value.country_code and value.national_number:
                    return ["+%d" % value.country_code, value.national_number]
            else:
                return value.split(".")
        return [None, ""]

    def value_from_datadict(self, data, files, name):
        values = super().value_from_datadict(data, files, name)
        if all(values):
            return "%s.%s" % tuple(values)
        return ""

    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)
        if self.is_localized:
            for widget in self.widgets:
                widget.is_localized = self.is_localized
        # value is a list of values, each corresponding to a widget
        # in self.widgets.
        if not isinstance(value, list):
            value = self.decompress(value)

        final_attrs = context['widget']['attrs']
        input_type = final_attrs.pop('type', None)
        id_ = final_attrs.get('id')
        subwidgets = []
        for i, widget in enumerate(self.widgets):

            if input_type is not None:
                widget.input_type = input_type
            widget_name = '%s_%s' % (name, i)
            try:
                widget_value = value[i]
            except IndexError:
                widget_value = None
            if id_:
                widget_attrs = final_attrs.copy()
                widget_attrs['id'] = '%s_%s' % (id_, i)
            else:
                widget_attrs = final_attrs.copy()
            if 'class' in widget.attrs:
                widget_attrs['class'] = widget.attrs['class']

            subwidgets.append(widget.get_context(widget_name, widget_value, widget_attrs)['widget'])

        context['widget']['subwidgets'] = subwidgets
        return context


class PhonePrefixSelect(Select):
    initial = None

    def __init__(self, initial=None, attrs=None):
        choices = [("", "---------")]
        language = translation.get_language() or settings.LANGUAGE_CODE
        self.attrs = attrs
        if language:
            locale = Locale(translation.to_locale(language))
            for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():
                prefix = "+%d" % prefix
                if initial and initial in values:
                    self.initial = prefix
                for country_code in values:
                    country_name = locale.territories.get(country_code)
                    if country_name:
                        choices.append((prefix, "{} {}".format(country_name, prefix)))
        super().__init__(choices=sorted(choices, key=lambda item: item[1]), attrs=attrs)

    def render(self, name, value, *args, **kwargs):
        return super().render(name, value or self.initial, *args, **kwargs)
@crukundo
Copy link

crukundo commented Dec 2, 2020

Maybe you could use the auto created field ids e.g #id_phone_0 and #id_phone_1 and apply your css to those respectively. Less intrusive.

@francoisfreitag
Copy link
Collaborator

Should have been fixed with #502

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants