insert and update depending on if the user has submitted information before

I have a custom form within a private member page allowing users to submit and update information to/from a database.

I want to check if the user has submitted information to the database before, and if so update their records, if not then to inout their records.

I’m not a coder, but this is what I’ve got so far.

I’m trying to use an if else. If the signed in user id equals the one in the database then update the records. If the id is not in the database then insert to the database.

Any help would be appreciated :slight_smile:

import wixData from 'wix-data';
import wixUsers from 'wix-users';

$w.onReady(function () {

});
export function buttonSubmit_click(event) {
    validation()
}

function validation() {
    let validationMessage = " ";
    if ($w("#input2").valid && $w("#input3").valid) {
        saveProperties();   
    } else {

        if (!$w("#input2").valid) {
            validationMessage += "Please enter a Business Name.\n"
        }

        if (!$w("#input3").valid) {
            validationMessage += "Please enter a Business Email Address.\n"
        }

        $w("#textErr").text = validationMessage
        $w("#textErr").show().then(() => {
            $w("#input2, #input3").updateValidityIndication()
        })
    }
}

function saveProperties() {
    $w('#buttonSubmit').disable()
    let uniqueClicks = 0
    let user = wixUsers.currentUser;
    let userId = user.id;
    let myQuery = wixData.query("Properties")

    let toInsert = {
        "businessName": $w("#input2").value,
        "businessEmail": $w("#input3").value,
        "uniqueClick": uniqueClicks
    };

    let toUpdate = {
        "businessName": $w("#input2").value,
        "businessEmail": $w("#input3").value,
    };

    myQuery.eq("_owner", userId)
    .find()
    .then((res)=>{
       if(res.items.length>0){
            console.log("Data found: ", res.items)
        wixData.update("Properties", toUpdate)
    .then ((results) => {
        let item = results;
        console.log(item);
        $w("#textErr").text = "Your information has been updated"
        $w("#textErr").show().then(() => {
            clearAllElements()
            $w("#buttonSubmit").enable()
            setTimeout(() => {
                $w("#textErr").hide()
            }, 5000
            )
        })
    })
    .catch((err) => {
        let errorMsg = err;
        console.log(errorMsg)
        });

        } else {
    wixData.insert("Properties", toInsert)
    .then ((results) => {
        let item = results;
        console.log(item);
        $w("#textErr").text = "Your information has been submitted"
        $w("#textErr").show().then(() => {
            clearAllElements()
            $w("#buttonSubmit").enable()
            setTimeout(() => {
                $w("#textErr").hide()
            }, 5000
            )
        })
    })
    .catch((err) => {
        let errorMsg = err;
        console.log(errorMsg)
    });
    }
})
    
function clearAllElements() {
    $w('#input2').value = null;
    $w('#input2').resetValidityIndication();
}}

So, I’ve done some testing and discovered the if a user hasn’t submitted any information yet, then it will allow them to do that. Although, if they have submitted information then it won’t allow them to update it. It appears as though when they click the submit button it causes it to disable

You need a record id in your toUpdate object. Also be aware that if you don’t include previous data in your toUpdate, it will get overwritten. update - Velo API Reference - Wix.com

Thanks for the help. Would you be able to explain in a little more detail about the record id in your toUpdate object. (New to code and don’t entirely know what you mean)

I’m planning on adding something like this so it doesn’t get overwritten:

wixData.get("Properties", $w('#id').text)
 .then((result) => {
            result.title = $w('#input2').value
            result.agentEmail = $w('#input3').value

It will populate all of the inputs and allow them to change the information they need to.

Each record in a Collection (database) has a record id - it’s probably hidden. It’s field name is _id. You need to include this record id in your update object so the code knows which record to update. You do not need an id for an insert - there is no id since the record has not been created, yet.

The way I code keeps evolving, but this is how I like doing my updates at the moment. Put the results of your query into a new object - that way you have all the data from the query (_id, all other field values). Then, in the new object, change only the fields you want to update. Use this new object to perform the update (you’ll have all the previous data from the results that you put in your new object and didn’t change).

myQuery . eq ( "_owner" ,  userId ) 
. find () 
. then (( res )=>{ 
   **if** ( res . items . length > 0 ){ 
        **let**  objResults  =  res . items [ 0 ]; 
        // You already have the record id objResults._id (res.items[0]._id)  
        // Change the fields you need to change, leave the rest 
        objResults .businessName =  toUpdate . businessName 
        objResults . businessEmail  =  toUpdate . businessEmail 

        console . log ( "Data found: " ,  res . items ) 
        wixData . update ( "Properties" ,  objResults )

The _id field wasn’t hidden.

So I’ve had a quick test of your’s and it appears to work. I’m wondering if it might be possible for me to still use the let toUpdate bit that I had before. It’s easier for me to update in the future should more fields be required

I’m not sure what you mean by using the “let toUpdate” bit.

As you get deeper into Velo, the API Reference will be your new best friend (API Overview - Velo API Reference - Wix.com). You might want to also look into using the backend for added security, although that might be more complicated than you want right now (Velo: Security Best Practices | Help Center | Wix.com).

@info26420 no worries. I hadn’t fully understood, but I understand it now.

It’s working and I think it’s at a point where I can scale it to include more inputs.

The API documentation is definitely my best friend already. I’ve learnt a lot in the last couple of months. Thanks for all the help :facepunch:

Just a quick one. If the user has already submitted data to the dataset and is trying to update it, I want to populate all of the input fields according to the information they have already submitted.

I assume this gets added in the section that is querying if the user has submitted data before.

I am currently using this:

wixData.get("Properties",$w('#id').text)
        .then((result)=>{
                result.title=$w('#input2').value
                result.agentEmail=$w('#input3').value

The problem is that it is bringing up someone else’s information. I need it to display the information of the person that has already submitted information.

I’d focus on what is being returned - if the wrong person’s information is being returned, then I’d first guess that you are using the wrong record id to get the record from your Properties dataset. Check that you’re not mixing up the Properties record id with the user id.

These two articles might be helpful:

Velo: Functional Testing in the Backend
https://support.wix.com/en/article/velo-functional-testing-in-the-backend

Velo: Testing and Debugging Your Code
https://support.wix.com/en/article/velo-testing-and-debugging-your-code#debugging-with-the-developer-console

@noahlovelldesign Lainie is providing you with the core concept that you need to get your arms around.

When you use the wix-user API you need to make sure you are using information from a logged in user.

It might be that your user is already logged in when they reach the page that this code is running on but you need to check this before you go much further.

If your user is not logged in then any user ID that you use will be random and untrustworthy.

Also you need to know if data has been entered before so the best way to do this is get the data you need when the page loads.

The pattern that you need to implement, as I understand your needs is something like this:

create global id variable
create global business data object

onReady
disable submit button
get the current user record
if the current user is logged in then
enable submit button
add the user id from the current user record to the global id variable
get the business properties from the “Properties”
if business properties returned
add business properties to global business data object
load business properties into the input elements displaying returned data
endif
else
tell user to login or register
endif
end onready

onSubmit button click
add new business properties to global business data object
if global business data object user id is null
update global business data object user id with global id variable value
update “Properties” using the global business data object
end onSubmit

A lot of the code you have written will work but you need to update it to include the test for user logged in and don’t allow an update if the user isn’t logged in.

I am happy to help you with more code but thought you might like a chance to make your own modifications.

Awesome! Thanks for the help. Much appreciated.

I’m new to code, so most of that has gone over my head :sweat_smile:. I’ll take some time reading over it to see what I can learn.

The client currently has this solution:
They have a button in the header of their website and 2 pages, one for submitting information and one for updating information.

The button checks if the logged in user has submitted information and directs them to each page depending on if their information is found in the database.

I was hoping to move it to one page as their are a few extra requirements that they need to include now, such as setting a number 0 in the database on the first submit only, and error messages etc. I thought it made sense to make it one page.

Noah

I have shared the general logic of what you ought to do to be safe.

I overlooked the point you made that this code is on a private member page. So assuming that the page can only be loaded by members then currentUser._id will get you a unique id and you don’t really need to check logged in status because the page shouldn’t load otherwise. Never hurts to check though.

One other point to note. Every user will have an entry in the crm database and that is accessed using the same user id.

The crm data collection already provides for a company name and company email address so it may pay to use this instead.

You will always get a crm record. Then all you need to do is update the company info as requested.

https://www.wix.com/velo/reference/wix-crm-backend/contacts-obj/appendorcreatecontact#wix-crm-backend_contacts-obj_appendorcreatecontact_how-the-data-is-handled

Thanks for that.

I’ve spent a few hours working on it and have decided to keep it as 2 separate pages, one for submitting and one for updating.

The only issue I am facing now is the uploading of images using the upload button.

I’m kind of hoping that I can use the let toInsert to insert the image. I’ve read the api documents and a whole ton of forum posts. Once I can figure out how to upload images to the database then I think I’ll have cracked it!

function saveProperties() {
    $w('#buttonSubmit').disable()
    let uniqueClicks = 0

    let toInsert = {
        "title": $w("#input2").value,
        "agentEmail": $w("#input3").value,
        "mapLocation": $w("#input36").value,
        "businessWebsite": $w("#input35").value,
        "facebook": $w("#input33").value,
        "instagramLink": $w("#input34").value,
        "hoursOfOperation": $w("#input37").value,
        "description": $w("#richTextBox1").value,
        "familyPic1": SOMETHING NEEDS TO GO HERE,
        "uniqueClick": uniqueClicks,
        "_userId": userId
    };

    wixData.insert("Properties", toInsert)
    .then ((results) => {
        let item = results;
        console.log(item);
        $w("#textErr").text = "Your information has been submitted"
        $w("#textErr").show().then(() => {
            $w("#buttonSubmit").enable()
            setTimeout(() => {
                $w("#textErr").hide()
                wixLocation.to("/update-pics-and-links");
            }, 5000
            )
        })
    })
    .catch((err) => {
        let errorMsg = err;
        console.log(errorMsg)
    });
    }

Hi Noah

First of all uploading images is done, as I’m sure you are aware using the upload button.

A trick here is that you can upload images immediately after selecting an image using the onChange handler.

The important aspects of accessing the selected image is that you need to actually upload the selected images to the media manager using the uploadFiles option to the uploadButton

Here’s some code as an example

let selectedFile = null;

$w.onReady(() => {
// force image type for upload
$w(“#uploadButton1”) .fileType = “Image”;
$w(“#uploadButton1”).onChange(getSelectedImage);

});

async function getSelectedImage(event) {
// uploadButton value has changed. If files were selected then upload it/them
let uploadedFiles = await $w(“#uploadButton1”).uploadFiles();
// we should have a list of uploaded file attributes
// we only need the first one if more than one is loaded
console.log(we uploaded ${uploadedFiles.length} files);
if (uploadedFiles.length > 0) {
// we have at least 1 file let’s use the first file as our selected file
selectedFile = uploadedFiles[0];
// Let’s show the selected image as confirmation of the upload
$w(“#selectedImageText”).text = Selected file name: ${selectedFile.fileName};
$w(“#selectedFileURL”).text = URL of selected files ${selected.fileUrl};

// Show image uploaded 
$w("#displayImage").src = selectedFile.fileUrl; 

}

}

======================
In the code above the important information that you need to access is the selectedFile.fileUrl

Now sometimes the url provided is not the url held in the media manager. If the image url when assigned to the sec property of an image element doesn’t render then search the forum for solutions on how to change the uploaded file url to view an image.

Thanks for the help, I really do appreciate it.

I’ve managed to get images to upload to the site, the problem I am currently facing is getting the selectedFile.fileUrl and adding it to the database so that it appears in the database

@noahlovell the code I have shared gets you to the record you need.

The variable “selectedFile“ is declared outside of all functions so it is a global variable and transcends all of your other function calls. If you have uploaded the image you need then the uploadFiles() function call you used will return the file objects in an array. The code I have shared extracts the first array record and puts it into the global variable selectedFile.

In your code where you say “something needs to go here” you should simply assign selecteFile.fileUrl.

Now if you have set the database property as text then that’s what you’ll get in the data collection. If you have set the property to image then you should see the image.

What is your database schema?
Make sure you use the correct record _id when you use update.

Perhaps if you share a url to your page it will make diagnosing the solution easier. Just comment out where you want the picture for now.