top of page

Forum Posts

stcroppe
Velo Expert
Velo Expert
Aug 12, 2019
In Coding with Velo
Now that it is possible to access Wix-CRM records directly using getContactById it should be possible to use Wix-users.register with the resulting contact record and NOT create a duplicate CRM record. Sequence of events: import wixCrm from ‘wix-crm-backend’; import wixUsers from ‘wix-users-backend’; export async function createUserFromCRM (firstName, lastName, email) { let contactId = await wixCrm.create ontact({firstName,lastName,emails[email]}); let contactInfo = await wixCrm.getContactById(contactId); contactInfo._id = contactInfo._id || contactInfo.id; // force ID let newUser = await wixUsers.register(email, “password”, {contactInfo}); // Should create a new user for an existing contact BUT creates a duplicate contact record instead. return newUser; } This code will create two contact records instead of reusing the first. I think this is a bug :-)
1
0
46
stcroppe
Velo Expert
Velo Expert
Sep 29, 2018
In Coding with Velo
Wix Team: There is a general set of problems associated with the mini cart on Wix Stores. Especially when used with mobile devices which makes Wix Stores on mobile clumsy and doesn't deliver a good experience. This is primarily associated with the add to cart functionality which forces the user to leave the current page to look at the cart even when they don't need to. 1. The capabilities provided in the $w.CartItem are not consistent with the options available in the $w.ProductPage element when it comes to disabling the minicart. $w.ProductPage permits you to disable the minicart from displaying in the Settings dialogue... By contrast this option is not available in the $w.CartIcon settings for when the function addToCart() is called, nor is it an option argument of the addToCart() function. 2. When "Open Mini Cart on click" in the Product Page settings is disabled and you add an item to your cart in mobile mode the Mini Cart is ALWAYS displayed regardless of the setting. Once this happens there is no way to go back to the page you were on other than to use the browser's back option. 3. When you disable the "Add To Cart" button on the $w.ProductPage element you lose access to the "Open Mini Cart on click" option. This sort of makes sense but it isn't clear if this setting is only active when the "Add To Cart" button is visible or if it is still active when the button is hidden. This wouldn't be a problem if this capability was moved to where it belongs (on the $w.CartIcon) or if it mirrored a similar setting on $w.CartIcon. 4. The $w.ProductPage has many useful settings accessible from UI settings but none that are accessible from Wix Code. For example it would be great to be able to have access to the "Add To Cart" event and perform additional or alternative tasks when it is clicked similar to the wix-router handler options beforeRouter and afterRouter. Having a beforeAddToCart() where the return value tells the Product Page element if it should continue with normal processing and an afterAddToCart() allowing for post add processing would be really helpful. Additionally having access to element properties on the element from code would be really helpful. 5. Permit the $w.ProductPage to be decorated in different ways. The experience should be similar to dragging elements into a Strip or ContentBox with errors or warnings being given if key elements are dragged out of the $w.ProductPage element scope. The store capabilities are pretty impressive at the moment but focus seems to be on Desktop use which may not be the predominant use case for Wix users. Cheers Steve
wix-stores: API inconsistencies creating bad mobile experience content media
9
8
718
stcroppe
Velo Expert
Velo Expert
Jul 30, 2018
In Coding with Velo
OK folks, has anyone seen this effect when using wix-router? Wix team not sure this is this a feature or a bug. I am however erring on the side of it being a bug. I have a date field in a data collection that I want to retrieve in my router and then pass to my page using the [routerReturnedData: Object] parameter of the ok() function. So I have an object (a raw record from the data collection) which I pass to the ok function. When I pull the record from the getRouterData() function on my page the record has been miraculously changed. To verify this phenomenon I sent a JSON version of the object along with the actual object from my router and this is what I get: JSON version of Original Object: {"_id":"89626c76-41a5-4011-bafb-b936c88437e1", "guestId":"d862cc5c-0e45-4f62-be1b-1e6299fa4ed3", "guestNotes":"Stuff", "requested":"2018-07-26T13:31:33.184Z", "_createdDate":"2018-07-26T13:31:39.137Z", "_updatedDate":"2018-07-26T13:31:39.137Z"} This arrives in an object as follows: {"guestId":"d862cc5c-0e45-4f62-be1b-1e6299fa4ed3", "guestNotes":"Stuff", "requested":{"$date":"2018-07-26T13:31:33.184Z"}, "_createdDate":{"$date":"2018-07-26T13:31:39.137Z"}, "_id":"89626c76-41a5-4011-bafb-b936c88437e1", "_updatedDate":{"$date": "2018-07-26T13:31:39.137Z"}} So basically the Wix api code has (possibly for JSON encoding purposes though it doesn't appear necessary) adjusted the original record and altered the date fields by turning them into Objects by adding the key "$date". It has then forgotten to rewind this adjustment when getRouterData() is called :-(. Cheers Steve
1
3
110
stcroppe
Velo Expert
Velo Expert
Jul 29, 2018
In Coding with Velo
I have an onClick() event handler on a repeater element. When I get this event I am setting up the selector scope using the new $w.at() method so: $('#repeatedElement').onClick((event) => { let scopeSelector = $w.at(event.context); }); When I load the dataset itemData using this scopeSelector I get the expected result. However when I try to get the index of the item data in the dataset I get zero. Is this a feature or a bug? So: $('#repeatedElement').onClick((event) => { let scopeSelector = $w.at(event.context); // This works... let itemData = scopeSelector('#dataset1').getCurrentItem(); // This returns an index of 0 no matter which item I clicked on // the repeater. Is this a side effect of the next at() implementation? // Note: I get the same effect if I re-instate the scoped selector // using (event, $w) => ... let itemIndex = scopeSelector('#dataset1').getCurrentItemIndex(); }); Cheers
0
7
1k
stcroppe
Velo Expert
Velo Expert
Jul 28, 2018
In Coding with Velo
Wix team - is there a pending deprecation of functionality in the Repeater API? Recently I have been advising some users about the scope of the selector variable and how it applies in action handlers like onClick. I have just noticed that the $w and $w.Repeater documentation has recently changed and now includes an at() function. This is now used in the action handler example for onClick(). I have numerous handler functions using the (event, $w (scoped)) event call vs. the new model: I have checks and the $w (scoped) implementation is still working. I just want to know when this is likely to stop working ;-) Thanks Steve
$w.Repeater API change / deprecation... content media
0
4
129
stcroppe
Velo Expert
Velo Expert
Jul 19, 2018
In Coding with Velo
Tom, Ben, Shlomi and the wix team I am happy to take guidance on what I may be doing wrong but I think we have incomplete or broken functionality here. I have been trying to develop a member registration page using the wix-users.register() in conjunction with either wix-users.emailUser() or wix-crm.emailContact(). The idea is as follows and is a derivative of the Register a user sending an email for confirmation process described in the wix-users.approveByToken() documentation here: https://www.wix.com/code/reference/wix-users-backend.html#approveByToken So the basic flow I am trying to perform includes wix.users/wix.users-backend/wix.crm/wix-crm-backend/wix-router and looks like this While trying to build this I have encountered some documentation errors and problems with Wix's assumptions associated with this process. Let's start with documentation errors: In this flow, from the documentation referenced above, there is a call to wix-users-backend.emailUser()... This function doesn't exist in wix-users-backend :-( It doesn't exist in wix-crm-backend either. So the only recourse is to use the client side version of either of these as follows: As you can see from the graphic, Wix on the client side assumes (quite rightly, possibly, for security purposes) that the user is known to the web site before permitting the email interface to be used. So in the case of wix-users the user must be logged in "User must be logged-in in order to send an email" before a triggered email can be sent. This, presumably, is because the wix-users interface actually ignores the contact id it wants in the argument list and wants to see the wix-users.currentUser.id there and the loggedIn status needs to be loggedIn (question here is - why bother with a contact id in the argument list if this is the case?). In the case of wix-crm things are a little more esoteric. It complains with "contactId does not match current session contact (401)" which is another way of saying "this user is not logged in" [;-)]. So even though the Wix documentation states you can use a deferred registration technique for enhanced security using approval tokens. You really can't :-). Lastly, there has been another thread addressing variable substitution in triggered emails. https://www.wix.com/code/home/forum/community-discussion/triggered-email-template-replace-variables-in-links One of the things you want to do in a triggered email is send a 'nice' looking email where complex URLs are masked in text or behind a button as a link. However, you cannot use variables in links on triggered emails which is a problem. Yes you can rely on a URL being clickable when added as text but tokens are long and complicated. So rather than present my prospective member with a text url that looks like: https://www.domain.com/membership/confirmRegistration/JWS.eyJraWQiOiJSc012MmV3MiIsImFsZyI6IkhTMjU2In0.eyJkYXRhIjoie1wiaWRcIjpcIjIzZWJhYmQ4LTVhZmMtNGY2Ny04ZjI1LTc1YjUxNzc4NThjOFwiLFwiY29sbGVjdGlvbklkXCI6XCIzZWY2NDk0MC1mZWUwLTQ3YTUtOGFmMy1mMDZjYzdlZDY1ZjJcIn0iLCJpYXQiOjE1MzE3NjE5MTksImV4cCI6MTUzMTc2MjIxOX0.Jam1VTdkrZlt_Fgc4T1Rq1MNQKzEo4y0-M4ZeR4IJy8 I would rather present them with either a text link: Click Here to Verify or a button One last point. Why doesn't wix-users also offer an equivalent login() function that permits a custom login page to be developed? Cheers Steve
wix-users/ wix-crm Registration using email with approvalToken problem content media
3
3
751
stcroppe
Velo Expert
Velo Expert
Jul 11, 2018
In Coding with Velo
The Repeater element comes with a neat 'animation' button that allows you to select animations to use when the repeater loads. This is wonderful when the page/repeater initially loads but doesn't get applied when the repeater is updated. So for example my expectation would be that whenever a connected dataset page updates (thereby requiring a new set of items being populated in the repeater) that the same animation is used to update the repeater items. Instead it seems that each data set is hidden without animation and the next set is shown without animation. This essentially means that I would need to write my own repeater if I want to animate page refreshes. Am I missing something or is this a bug (unintended feature)?
1
2
192
stcroppe
Velo Expert
Velo Expert
Jul 10, 2018
In Coding with Velo
I am not sure if this is a feature request or a bug :-). I have been struggling to understand how to add data to the CRM Custom Fields and thought I would literally follow one of the wix-crm examples. It turns out that in order to use Custom `Fields you actually have to use the key "customField<number>" in the wix-crm API. This is counter intuitive and not what the documentation states :-( When setting a custom field, use key:value pairs where the key matches the names defined in your site's Contacts List. You can only set values for custom fields that already exist in the Contacts application. When I read this it tells me that if I created a custom field called say Credit Card Expiration in my Contact Record then when I want to populate the property Credit Card Expiration then my code should look like this: let contactRecord = { 'Credit Card Expiration':value } or perhaps let contactRecord = { 'CreditCardExpiration':value } or perhaps let contactRecord = { 'creditCardExpiration':value } However what I need to do is figure out which custom field I want to populate by going to the Custom Field form in the CRM... Then I need to count down to the field I want to populate so Credit Card Expiration is position number 3 therefore in wix-crm/wix-users to populate Credit Card Expiration I need to use the key customField3 so my code needs to look like: let contactRecord = { 'customField3':value }; // Set property for Credit Card Expiration Can the Wix team please update the documentation to be more clear on this point OR better still provide a way to either add the wix-crm key in the Custom Field dialogue OR provide a simple algorithm such as : All Custom Field Names will be converted to a camel case key by removing white space, converting all characters to lowercase with the exception of the first letter of all words following whitespace e.g. Credit Card Expiration -> creditCardExpiration GDPR Opt Out -> gdprOptOut
wix-crm/wix-users: Contact Record Custom Field Names content media
0
12
1k
stcroppe
Velo Expert
Velo Expert
Jul 05, 2018
In Coding with Velo
I saw a request recently for a repeater to be able to manage a slide show or a repeater to perform as a slide show. None of these options is trivial if you try to use the $w.Repeater or $w.Slideshow APIs. Using them is probably a little bit of over kill anyway when all you want to do is change a single container and some key property elements using data from a data set. Here is one approach. Step 1: Create your slideshow data collection and populate it with whatever you want in your slide show. Then in the Wix Editor connect up the datacollection using a dataset connector. We will name the dataset '#slideContent'. We can adjust the number of items per page depending on the number of elements we are showing. Step 2: Create the baseline element with the property elements that you want. So for this example we will use a $w.ColumnStrip. The columnStrip will have a single $w.Text element for an image title and we will use the $w.ColumnStrip background image to render an image in our slider. Step 3: Clone the Strip by right clicking the $w.ColumnStrip element and selecting "Duplicate". Now name the $w.ColumnStrip and the $w.Text elements something that makes sense for your site. I have used #columnStrip1 which contains #title1, and #columnStrip2 which contains #title2. Make sure that the two $w.ColumnStrips overlap each other (one is superimposed on the other). We will use these to create the slide show effect. Step 4: Create a slide change control to manage slide transition. I did this using a $w.Box that slightly overlaps the $w.ColumnStrip elements. This prevents the editor from adding the controls as children of the top most $w.ColumnStrip which we don't want. Make the $w.Box background transparent by setting the opacity to 0. I chose an arrow design $w.VectorImage for the left and right arrows and named the elements #left and #right. Step 5: We need to wire up the arrows for our controls to move the slides left and right. You can do this in two ways. Firstly you can add onClick() handlers into the $w.onReady() function override OR you can bind the element via its property page. I chose the latter. Which results in the Wix Editor adding a function hook into the code page for you external function right_click() Step 6: Now we can add some code to the page to create our SlideShow: let isOdd = true; $w.onReady(function () { // Make sure our slide data is loaded before we try to load up our // first slide $w('#slideContent').onReady(() => { showNewItem($w('#slideContent').getCurrentItem()); }); }); /* function: showNextItem description: Uses data from our data set to populate the next slide and when loaded swaps it with the one currently visible arguments: item - the database record direction - which way to animate our slide */ function showNewItem(item, direction) { if (item && item['title'] && item['photo']) { let nextSlide = getNextStrip(); let strip = nextSlide[0]; let title = nextSlide[1]; strip.background.src = item['photo']; title.text = item['title']; swapSlides(direction); } } /* function: getNextStrip description: Simple toggle function to select the elements we need to populate for the next slide. The 'isOdd' property is used to choose which elements we are interested in. It gets toggled before we exit. arguments: none */ function getNextStrip() { let result = []; if (isOdd) { result.push($w('#columnStrip1')); result.push($w('#title1')); } else { result.push($w('#columnStrip2')); result.push($w('#title2')); } // Toggle the element selector isOdd = !isOdd; return result; } /* Function: swapSlides Description: This function performs the slide show rendering It makes use of the fact that effects are performed using Promises and collects the effect promises show() and hide() in a super promise using the all() function. Direction is flowed down to the show and hide methods which control animation Arguments: direction - either 'left' or 'right' */ function swapSlides(direction) { let keepMyPromise = null; if (isOdd) { keepMyPromise = Promise.all( [ hide($w('#columnStrip1'), direction), show($w('#columnStrip2'), direction) ]); } else { keepMyPromise = Promise.all( [ show($w('#columnStrip1'), direction), hide($w('#columnStrip2'), direction) ]); } // Returns the Promise we created in case the calling function // has something else to do after return keepMyPromise; } /* Function: hide Description: Creates a simple overlay on the normal $w.HiddenMixIn API to apply Effect filters to the hide() function Arguments: element - the $w() element that we are hiding direction - 'left' or 'right' for slide egress direction */ function hide(element, direction) { let slideEffect = { "direction": 'right' }; if (direction === 'right') { slideEffect.direction = 'left'; } // Note we are using 'fade' here. It was originally 'slide' but the // effect was not a good one if you want to use slide then remove // the fade and uncomment out this code: // return element.hide('slide', slideEffect); return element.hide('fade'); } /* Function: hide Description: Creates a simple overlay on the normal $w.HiddenMixIn API to apply Effect filters to the hide() function Arguments: element - the $w() element that we are showing direction - 'left' or 'right' for slide egress direction */ function show(element, direction) { let slideEffect = { "direction": 'left' }; if (direction === 'left') { slideEffect.direction = 'right'; } return element.show('slide', slideEffect); } /* ****** Element handler functions Function: right_click Description: fires when the right $w.VectorImage is clicked. Used to advance the slide show to the right by using the dataset $w('#slideContent') next() function or resetting the dataset index to 0 if we have reached the end of the data set. This creates a circular slide effect. Arguments: event - the event object associated with the click $w - the page scope variable for our element management Returns: a promise that should resolve to the next item from the data set which is ".then()" passed to our showNewItem function where the slide show effect happens! */ export function right_click(event, $w) { let dataset = $w('#slideContent'); let keepMyPromise = null; if (dataset.getCurrentItemIndex() === dataset.getTotalCount() - 1) { // We need to reset to the start of the slide show keepMyPromise = dataset.setCurrentItemIndex(0) .then(() => { return Promise.resolve(dataset.getCurrentItem()); }); } else { // Get the next item keepMyPromise = dataset.next(); } return keepMyPromise .then((newItem) => { showNewItem(newItem, 'right'); }); } /* Function: right_click Description: fires when the right $w.VectorImage is clicked. Used to advance the slide show to the right by using the dataset $w('#slideContent') previous() function or resetting the dataset index to the end of the dataset if we have reached the beginning of the dataset. This creates a reverse circular slideshow effect. Arguments: event - the event object associated with the click $w - the page scope variable for our element management Returns: a promise that should resolve to the next item from the data set which is ".then()" passed to our showNewItem function where the slide show effect happens! */ export function left_click(event, $w) { let dataset = $w('#slideContent'); let keepMyPromise = null; if (dataset.getCurrentItemIndex() === 0) { // We need to reset to the start of the slide show keepMyPromise = dataset.setCurrentItemIndex(dataset.getTotalCount() - 1) .then(() => { return Promise.resolve(dataset.getCurrentItem()); }); } else { // Get the next item keepMyPromise = dataset.previous(); } return keepMyPromise .then((newItem) => { showNewItem(newItem, 'left'); }); } I hope some of you find this useful. Steve
Dynamic Slideshow using Dataset content media
4
12
6k
stcroppe
Velo Expert
Velo Expert
Jun 25, 2018
In Coding with Velo
According to the wix users and router documentation these are the core roles that expected in the user role property: role Gets the user's role. Syntax get role(): String Description Gets one of the following roles: "Admin" — The owner of the site. "Member" — A user who is logged in. "Visitor" — A user who is not logged in. I am trying to use the wix-router for an admin authenticated set of pages. In my testing the test if (request.user.role === 'Admin') { } kept failing so I created a 'sendStatus' page to display the role being retrieved and it turns out that one of the roles the user returns is also 'siteOwner'. Is this intended or is this a bug? Either way the bug needs to be resolved OR the api docs need to be updated ;-)
0
5
173
stcroppe
Velo Expert
Velo Expert
Jun 20, 2018
In Coding with Velo
I am trying to create a contact record using the users register() method. I am providing all valid parameters but get the following error back. Hopefully the following stack trace helps. I wonder if it is something to do with the createContact 500 error? Error: server responded with 500 - {"message":"Internal Server Error"} at Object.<anonymous> (wix-users-backend/src/users.ts:68:11) at Generator.throw (<anonymous>) at rejected (wix-users-backend/dist/src/users.js:5:65) at bound (domain.js:301:14) at runBound (domain.js:314:12) at tryCatcher (node_modules/bluebird/js/main/util.js:26:23) at Promise._settlePromiseFromHandler (node_modules/bluebird/js/main/promise.js:510:31) at Promise._settlePromiseAt (node_modules/bluebird/js/main/promise.js:584:18) at Async._drainQueue (node_modules/bluebird/js/main/async.js:128:12) at Async._drainQueues (node_modules/bluebird/js/main/async.js:133:10) at Immediate.Async.drainQueues (node_modules/bluebird/js/main/async.js:15:14) at runCallback (timers.js:789:20) at tryOnImmediate (timers.js:751:5) at processImmediate [as _immediateCallback] (timers.js:722:5)
0
8
1k
stcroppe
Velo Expert
Velo Expert
Jun 18, 2018
In Coding with Velo
I have tried to make use of this api to effect a triggered Guest email exchange. Despite following the api guide I am constantly getting the following error: server responded with 400 - {"message":"Bad Request"} The back end code I am using is: import wixData from 'wix-crm-backend'; export function backendCrmCreate(first, last, email, phone, a_label, newDate) { let contactRecord = { 'firstName':first, 'lastname':last, 'labels':['a_label'], 'emails':[email], 'phones':[phone], 'newDateField': newDate }; console.log(contactRecord); // Inorder to send emails to this customer we need to have a crm record. // We will create one for this purpose return wixCRM.createContact(contactRecord) .then((contactId) => { do stuff return Promise.resolve(result); }) .catch((error) => { console.log(error); }); } Apart from anything else, this is not very helpful and doesn't help me figure out what is broken. The crm and crm-backend api's I expected to behave in a similar way to wix-data. i.e. user authentication is required to use crm api calls on front end code and admin privileges are automatic for backend code (or authentication is supressed). In addition because of the lack of a Single Sign On/ unique record capability (e.g. only one record can contain a given email), the crm can contain duplicate records for contacts. This (I am sure) would make it difficult for the existing crm api to work effectively without either generating new records or getting confused about which record to return (unless it defaults to Member records). Any feedback would be helpful
1
3
577

stcroppe

Velo Expert
+4
More actions
bottom of page