2

I’m using the USelectMenu component from the Nuxt UI library, and I need to ensure that all the options that the user can select are displayed. I have that covered with my mapped_looking_for method, and the options are bound correctly. Then, I need to display all the options that the user has already selected, which I also have working to some extent.

The problem is that the select should work in such a way that if an option is selected, there should be a tick next to it on the right indicating that it is indeed selected. However, even though it shows that 5 options are selected, I don't see the tick next to them. I am also unable to interact with them in such a way that I could remove options. Essentially, it doesn't work for me; I would have to manually delete them from the database.

Could anyone offer some advice? I’m relatively new to working with APIs, and I might be passing the data incorrectly. Thank you.

This is frontend.

<template>
    <div class="">
        <Heading as="h2">
            <span>Your profile</span>
        </Heading>
        <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
            <form @submit.prevent="updateProfile">

                <Heading>
                    <UAvatar :src="getAvatarUrl(profile.avatar)" size="xl" />

                </Heading>

                <UFormGroup label="About me">

                    <UTextarea autoresize color="primary" placeholder="Search..." v-model="profile.bio" />
                </UFormGroup>

                <UFormGroup label="Name">
                    <UInput color="primary" disabled v-model="user.name" />
                </UFormGroup>

                <UDivider label="Stats" class="mt-5" />
                <UFormGroup label="Show age">

                    <UToggle on-icon="i-heroicons-check-20-solid" off-icon="i-heroicons-x-mark-20-solid"
                        v-model="profile.show_age" />
                </UFormGroup>
                <UFormGroup label="Age">
                    <UInput color="primary" disabled v-model="profile.age" />
                </UFormGroup>
                <UFormGroup label="Height">
                    <USelect color="primary" v-model="profile.height" :options="height_option" />
                </UFormGroup>
                <UFormGroup label="Weight">
                    <USelect color="primary" v-model="profile.weight" :options="weight_option" />
                </UFormGroup>
                <UFormGroup label="Body Type">
                    <USelect color="primary" v-model="profile.body_type" :options="body_types" />
                </UFormGroup>
                <UFormGroup label="Relationship Status">
                    <USelect color="primary" v-model="profile.relationship_status" :options="relationship_status" />
                </UFormGroup>
                <UDivider label="What are you looking for?" class="mt-5" />

                <USelectMenu v-model="selected_looking_for" :options="mapped_looking_for" multiple
    placeholder="Vyber, co hledáš"  value-field="value" label-field="label" 
    />
                <div class="selected-options">
                    <UBadge v-for="item in profile.looking_fors" :key="item.id" :label="item.name" color="primary"
                        class="mr-2 mb-2 mt-2" />
                </div>
                <UDivider label="Identity" class="mt-5" />
                <UFormGroup label="Gender">
                    <USelect color="primary" v-model="profile.gender" :options="genders" />
                </UFormGroup>
                <div class="flex justify-center mt-4">
                    <UButton color="primary" size="md" type="submit">
                        Save
                    </UButton>
                </div>
            </form>


        </div>
    </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const { api } = useAxios();
const profile = ref({});

const user = ref({});

const mapped_looking_for = ref([]);
const selected_looking_for = ref([]);
const genders = ['male', 'female']

const height_option = ref([{ label: 'Do not show', value: 'Do not show' }]);

const weight_option = ref([{ label: 'Do not show', value: 'Do not show' }]);

const relationship_status = ["Do not show", "Commited", "Dating", "Engaged", "Exclusive", "Married", "Open Relationship", "Partnered", "Single"]

const body_types = ["Do not show", "Toned", "Average", "Large", "Muscular", "Slim", "Stocky"]

const fetchLookingFor = async () => {
    try {
        const { data } = await api.get('/api/lookingFor');
        mapped_looking_for.value = data.data.map(item => ({
            label: item.name,
            value: item.id
        }));
        console.log('Mapped looking_for:', mapped_looking_for.value);
    } catch (error) {
        console.error('Error fetching looking for options:', error);
    }
};




const fetchProfile = async () => {
    try {
        const { data } = await api.get('/api/profiles/show');
        profile.value = data.profile;
        user.value = data.user;
        selected_looking_for.value = data.looking_fors.map(item => item.id);
    } catch (error) {
        console.error('Error fetching profile:', error);
    }
};


// Updating profile
const updateProfile = async () => {
    try {
        const looking_for_id = selected_looking_for.value.map(item => item.value);

        await api.put(`/api/profiles/${profile.value.id}`, {
            bio: profile.value.bio,
            gender: profile.value.gender,
            show_age: profile.value.show_age,
            height: profile.value.height,
            weight: profile.value.weight,
            body_type: profile.value.body_type,
            relationship_status: profile.value.relationship_status
        });

        await api.put(`/api/profiles/${profile.value.id}/looking-for`, {
            looking_for: looking_for_id
        });
        console.log('Profile updated successfully');
    } catch (error) {
        console.error('Error updating profile:', error);
    }
};


const getAvatarUrl = (avatarPath) => {
    const baseUrl = 'http://localhost:8080';
    return `${baseUrl}/storage/${avatarPath}`;
};

watch(() => profile.value.show_age, async (new_value) => {
    try {
        await api.put(`/api/profiles/${profile.value.id}`, {
            show_age: new_value
        });
        console.log('Show age updated successfully');
    } catch (error) {
        console.error('Error updating profile:', error);
    }
});


// height select

for (let i = 120; i <= 230; i++) {
    height_option.value.push({
        label: `${i} cm`,
        value: `${i}`
    });
}

// weight select

for (let x = 40; x <= 270; x++) {
    weight_option.value.push({
        label: `${x} kg`,
        value: `${x}`
    })
}

onMounted(() => {
    fetchProfile();
    fetchLookingFor();
});

</script>

This is what I have on backend.

 public function show(): JsonResponse
    {
        $user = Auth::user();

        $profile = $user->profile;

        return response()->json([
            'user' => [
                'name' => $user->name,
                'email' => $user->email,
            ],
            'profile' => $profile,
            'looking_fors' => $profile->lookingFors
        ]);
    }

 public function updateLookingFor(Request $request): JsonResponse
{
    $user = $request->user();
    $profile = $user->profile;
    $validated = $request->validate([
        'looking_for' => 'array',
        'looking_for.*' => 'exists:looking_fors,id',
    ]);

    $profile->lookingFors()->sync($validated['looking_for']);

    return response()->json(['message' => 'Looking for updated successfully']);
}

// And route

    Route::put('/profiles/{id}/looking-for', [ProfileController::class, 'updateLookingFor']);

Additional infos: This is the payload for the initial request when the user doesn't have anything saved in the looking_for field in the pivot table profiles_looking_fors:

{looking_for: [1, 2, 3]}

It stores the id of the respective looking_for, which is correct.

However, when I select the same values again (which essentially means I want to deselect them or remove them from the database to make it work in both directions), an error occurs:

"errors": {
    "looking_for.0": [
        "The selected looking_for.0 is invalid."
    ],
    "looking_for.1": [
        "The selected looking_for.1 is invalid."
    ],
    "looking_for.2": [
        "The selected looking_for.2 is invalid."
    ]
}

This is the payload: after errors

{looking_for: [null, null, null, 1, 2, 3]}

It sends null values along with 1, 2, 3.

9
  • it seems fetchProfile is defined but not being triggered! and the code that changes the selected is in that function, also if you could include the '/api/profiles/show' code that would be great Commented Oct 17, 2024 at 11:45
  • Also the v-model you are using looking_fors which is undefined, you should use looking_for Commented Oct 17, 2024 at 11:55
  • @Mohammadsiabbou I did updated the question and provided full code of forntend and backend method for profile show, and i am mounting data properly from profile Commented Oct 17, 2024 at 12:59
  • I think the issue is here selected_looking_for.value = data.profile.looking_fors.map(item => item.id); it should be selected_looking_for.value = data.looking_fors.map(item => item.id); since you are passing it as its own key, please try it and tell me the result Commented Oct 17, 2024 at 14:18
  • @Mohammadsiabbou I did try your adviced solution, and it didn't help unfortunately, but i provided more info about a problem in question. Commented Oct 18, 2024 at 12:21

1 Answer 1

0

I managed to solve the problem by creating my own multiselect component instead of using the one from the Nuxt UI library. The issue was with the Nuxt UI component itself, as I found on their GitHub issues page that it looks like it struggles to properly set the initial values when is user fetching data from backend API.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.