My Button Requires Two Clicks

I have written the following code to save (to a collection) the contents of several input fields and an HTML box running CKEditor in it (as Wix don’t yet support a Rich Text Editor Input Field in Editor X for some reason). The code seems to work fine with one huge exception…I need to click the submit button twice to get it to work.

I suspect this is something to do with the way I am communicating with CKEditor but I am hoping one of you more experienced folks can help me understand what is wrong here. Thanks in advance for your thoughts. The code is below (the second two import sections at the top are there for code that isn’t written yet).

Simon.

import wixUsers from 'wix-users';
import wixData from "wix-data";
import wixWindow from 'wix-window';
import {sendEmail} from 'backend/sendEmail';

//Adds an event handler that runs when the element is clicked.

var userEmail;
var orgName;

export function button1_click(event) {
 // Send a blank message to the HTML element. This tells the HTML 
 // element you want it to send you its contents 
$w("#html1").postMessage(" ");
// add an event handler to receive the message from the HTML element
$w("#html1").onMessage( (event) => {
 let receivedData = event.data;

 let toSave = {
 "title": $w('#title').value,
 "longDescription": receivedData,
 "shortDescription": $w('#shortDescription').value,
 "closingDate": $w('#closingDate').value,
 "salary": $w('#salary').value,
 "contractType": $w('#contractType').value,
 "hours": $w('#hours').value,
 "location": $w('#location').value,
 "applicationUrl": $w('#applicationUrl').value,
 "applicationEmail": $w('#applicationEmail').value,
 "author": $w('#author').value,
 "organisation": $w('#orgName').value,
};

wixData.save("JobPage", toSave)
 .then( (results) => {
 let item = results; //see item below
 console.log(item);
 } )
 .catch( (err) => {
 let errorMsg = err;
 } );
 });
};

$w.onReady(function () {

popFields();

});

function popFields() {
 wixData.query("Members/PrivateMembersData")
 .eq("_id", wixUsers.currentUser.id)
 .find()
 .then((results) => {
 let record = results.items[0];
 $w('#author').value = record.name;
 userEmail = record.loginEmail;
 
 console.log(userEmail);

 wixData.query("IndividualsInfo")
 .contains("email", userEmail)
 .find()
 .then((results2) => {
 orgName = results2.items[0].org;
 $w('#orgName').value = orgName;

 });
 });
}

You set up the event handler for the HTML box only after a button click.

export function button1_click(event) {
 /* ... */
 $w("#html1").onMessage((event) => {
 /* ... */
 });
}

I guess the event handler not ready on the first click. Try to move the event handler for the HTML box to $w.onReady

The second reason move the event handler to $w.onReady method: each time when you click the button it set new and new event handlers for HTML box.

$w.onReady(() => {
 $w("#html1").onMessage((event) => {
 /* ... */
 });
})

Thanks Alexander. Wix won’t let me move the export function inside the $w.onready method…it says the export needs to be at the top level.

I will see what else I can manage along these lines though. More later.

I modified my code…and I think I did so as you recommended. There’s some extra code in here for error checking on the form and checking to see if user is a member to determine the next step…otherwise very similar to before and it still (unfortunately) requires two clicks on the button to submit.

I am including the code from the CKeditor html box as well (should have done last time as perhaps the issue lies there).

Really need some help here folks…I have been struggling with this for weeks. Would have been EASY if there was a rich text input field in Editor X…wouldn’t have needed any of this custom code at all.

import wixUsers from 'wix-users';
import wixData from "wix-data";
import wixWindow from 'wix-window';
import {sendEmail} from 'backend/sendEmail';

//Adds an event handler that runs when the element is clicked.
var userEmail;
var orgName;
var org_id;


$w.onReady(function () {

//pull data from other collections about the user, for pre-populated fields
popFields();

//
$w("#button1").onClick( (event) => {

 // Send a blank message to the HTML element. This tells the HTML 
 // element you want it to send you its contents 
$w("#html1").postMessage(" ");
// add an event handler to receive the message from the HTML element
$w("#html1").onMessage( (event) => {
 let receivedData = event.data;

if (!$w("#title").valid || !$w("#shortDescription").valid || !$w("#hours").valid || !$w("#location").valid || !$w("#closingDate").valid) {
 //build an error message
 let validationMessage = '';
 
 if (!$w('#title').valid){
 validationMessage += 'Check Job Title field\n';
 }
 if (!$w('#shortDescription').valid){
 validationMessage += 'Check Position Summary field\n';
 }
 if (!$w('#hours').valid){
 validationMessage += 'Check Hours field\n';
 }
 if (!$w('#location').valid){
 validationMessage += 'Check Location field\n';
 }
 if (!$w('#closingDate').valid){
 validationMessage += 'Check the Closing Date field\n';
 }

 $w('#text42').text = validationMessage;
 $w('#text42').show();
 } 

 //else submit data to collection
 else { 
 let toSave = {
 "title": $w('#title').value,
 "longDescription": receivedData,
 "shortDescription": $w('#shortDescription').value,
 "closingDate": $w('#closingDate').value,
 "salary": $w('#salary').value,
 "contractType": $w('#contractType').value,
 "hours": $w('#hours').value,
 "location": $w('#location').value,
 "applicationUrl": $w('#applicationUrl').value,
 "applicationEmail": $w('#applicationEmail').value,
 "author": $w('#author').value,
 "organisation": org_id,
 };

 wixData.save("JobPage", toSave)
 .then( (results) => {
 let item = results; //see item below
 //is user logged in?
 let user = wixUsers.currentUser;
 let isLoggedIn = user.loggedIn; // true
 if (isLoggedIn){
 wixWindow.openLightbox("MemberJobPayment");
 }
 else {
 wixWindow.openLightbox("NonMemberJobPayment");
 }
 } )
 .catch( (err) => {
 let errorMsg = err;
 wixWindow.openLightbox("FailedPost");
 } );
 };
});
});
});


function popFields() {
 wixData.query("Members/PrivateMembersData")
 .eq("_id", wixUsers.currentUser.id)
 .find()
 .then((results) => {
 let record = results.items[0];
 $w('#author').value = record.name;
 userEmail = record.loginEmail;
 
 wixData.query("IndividualsInfo")
 .contains("email", userEmail)
 .find()
 .then((results2) => {
 orgName = results2.items[0].org;
 $w('#orgName').value = orgName;

 wixData.query("MemberOrgs")
 .contains("sortName", orgName)
 .find()
 .then((results3) => {
 org_id = results3.items[0]._id;
 });
 });
 });
}


Code from html block:

<!doctype html>
<html>
  <head>
    <!--Define the character set for the HTML element -->
    <meta charset="utf-8">
    
    <!--Call the external script to use the CDN CKEditor in your page-->
    <script src="//cdn.ckeditor.com/4.16.1/basic/ckeditor.js"></script>  
    <script type="text/javascript">
	
    //Define an init function that sends the rich text editor contents to the page code
     function init() {       
       //onMessage runs when the HTML element receives a message from the page code
       window.onmessage = (event) => {  
         if (event.data) {
           //postMessage sends the contents of the CKEDITOR back to the page code
           window.parent.postMessage(CKEDITOR.instances.CK1.getData(),"*"); 
         }
       }
     }
     </script>
  </head>

  <body onload="init();">
    <!--Define the HTML element as a textarea-->
    <textarea name="editor1" id="CK1"></textarea> 
    <script>
        //Use the CKEditor replace() function to turn our textarea into a CKEditor rich text editor

    CKEDITOR.addCss('.cke_editable p { margin: 0 !important; }');
    CKEDITOR.addCss('.cke_editable a:link { color: blue !important; }');
    CKEDITOR.replace("editor1", {
      height: 630
    });
    </script>

Thanks,
Simon

I mean you should set up onMessage event handler outside of the onClick . If you set up the onMessage inside onClick then the onMessage isn’t ready to handle the response, onMessage will set up only after onClick .

You should set up onMessage early.


$w.onReady(() => {
 $w('#html1').onMessage((event) => {
   /* all logic of handling is going here */
  });

 $w('#button1').onClick( (event) => {
   $w('#html1').postMessage(' ');
  });
});

Before I say this, I really appreciate you helping me here, but I don’t think the page being ready is the problem. I am able to get it to work flawlessly on one click simply by sending the blank message to the html block twice…no delay at all…I don’t think it’s a timing issue, it’s some kind of sequencing issue in the code.

Hi Alexander. I got some time to implement your suggestion now and you were 100% right…and I have partially wrapped my head around what you were suggesting ( sorry for being slow ). Thanks for the help. Final code below:

import wixUsers from 'wix-users';
import wixData from "wix-data";
import wixWindow from 'wix-window';
import {sendEmail} from 'backend/sendEmail';

//Adds an event handler that runs when the element is clicked.
var userEmail;
var orgName;
var org_id;


$w.onReady(function () {

// add an event handler to receive the message from the HTML element
$w("#html1").onMessage( (event) => {
 let receivedData = event.data;

//pull data from other collections about the user, for pre-populated fields
popFields();

//field validation/error detection
if (!$w("#title").valid || !$w("#shortDescription").valid || !$w("#hours").valid || !$w("#location").valid || !$w("#closingDate").valid) {
 //build an error message
 let validationMessage = '';
 
 if (!$w('#title').valid){
 validationMessage += 'Check Job Title field\n';
 }
 if (!$w('#shortDescription').valid){
 validationMessage += 'Check Position Summary field\n';
 }
 if (!$w('#hours').valid){
 validationMessage += 'Check Hours field\n';
 }
 if (!$w('#location').valid){
 validationMessage += 'Check Location field\n';
 }
 if (!$w('#closingDate').valid){
 validationMessage += 'Check the Closing Date field\n';
 }

 $w('#text42').text = validationMessage;
 $w('#text42').show();
 } 

 //else submit data to collection
 else { 
 let toSave = {
 "title": $w('#title').value,
 "longDescription": receivedData,
 "shortDescription": $w('#shortDescription').value,
 "closingDate": $w('#closingDate').value,
 "salary": $w('#salary').value,
 "contractType": $w('#contractType').value,
 "hours": $w('#hours').value,
 "location": $w('#location').value,
 "applicationUrl": $w('#applicationUrl').value,
 "applicationEmail": $w('#applicationEmail').value,
 "author": $w('#author').value,
 "organisation": org_id,
 };

 wixData.save("JobPage", toSave)
 .then( (results) => {
 let item = results; //see item below
 //is user logged in?
 let user = wixUsers.currentUser;
 let isLoggedIn = user.loggedIn; // true
 if (isLoggedIn){
 wixWindow.openLightbox("MemberJobPayment");
 }
 else {
 wixWindow.openLightbox("NonMemberJobPayment");
 }
 } )
 .catch( (err) => {
 let errorMsg = err;
 wixWindow.openLightbox("FailedPost");
 } );

 };

});

$w("#button1").onClick( (event) => {

 // Send a blank message to the HTML element. This tells the HTML 
 // element you want it to send you its contents 
$w("#html1").postMessage(" ");
});

});


function popFields() {
 wixData.query("Members/PrivateMembersData")
 .eq("_id", wixUsers.currentUser.id)
 .find()
 .then((results) => {
 let record = results.items[0];
 $w('#author').value = record.name;

 userEmail = record.loginEmail;
 
 wixData.query("IndividualsInfo")
 .contains("email", userEmail)
 .find()
 .then((results2) => {
 orgName = results2.items[0].org;
 $w('#orgName').value = orgName;

 wixData.query("MemberOrgs")
 .contains("sortName", orgName)
 .find()
 .then((results3) => {
 org_id = results3.items[0]._id;
 });
 });
 });
}

It looks great!