I want to redirect user from one LWC to another by clicking on URL in experience cloud. Basically, on my first LWC I am showing the list of records retrieved from Apex and then when any row is clicked, I want to pass recordId of that row and redirect to second LWC which will show the record details page. How can I achieve this?
Do you have a Community... sorry, Experience Builder page with that target LWC dropped?
You could use NavigationMixin although documentation says communities don't support the state property.
On source side try something like
/* Assumes the link/button clicked looks like
<button data-id={acc.Id} onclick={handleClick}>Get details</button>
*/
handleClick(event){
if(event.currentTarget.dataset.id){
this[NavigationMixin.Navigate]({
type: 'comm__namedPage',
attributes: {
name: 'MyTargetCommunityPage__c'
},
state: {
id: event.currentTarget.dataset.id
}
});
}
}
And then on target page's LWC it should be accessible as
connectedCallback() {
if(window.location.href){
try{
let url = new URL(window.location.href);
var id = url.searchParams.get('id');
if(id){
this.myId = id;
}
} catch(e){
if(console){
console.log(JSON.stringify(e));
}
}
}
}
If Navigation gives you hard time you can ditch it and go straight for window.open('/pagename?id=123', _self); or something. It's bit annoying that you have 1 set of rules for core Salesforce, 1 for community.
(if you have a namespace - you might need to use myns__id in the state instead of id)
Related
I am working on a nextjs/typescript project that helps users to create a list of items they want to purchase.
When a user has purchased an items, they come to the application and tick that it has been purchased. Whenever this happens, I have to update the cart on my database (firestore)
The problem is that the code I use to update the database gives me the following error on the browser:
picture of error on browser
Below is my code when the user clicks on the item.
async function toggleItemIsCompletedState() {
dispatch(
cartActions.toggleIsCompletedState({
itemId,
categoryName: props.category,
})
);
// update cart in firebase
// ================================================
// For some reason I am not able to get the updated data to push to firestore so I am going to duplicate
// the code for updating the redux-store here so I can get updated data before pushing it.
const updatedItems = toggleItemIsCompletedStateUtil(
items,
props.category,
itemId
);
if (updatedItems === false) return;
console.log(updatedItems);
const cartData: CurrentCartUploadType = {
cartTitle,
items: updatedItems,
totalQuantity,
cartState,
isEditingCart,
};
// console.log("CartData: ", cartData);
const response = await updateCart(cartData);
console.log(response);
// ================================================
}
I viewed the docs and the solution was to use Effect but there are so many dependencies that the program would always keep re-rendering besides I tried using useEffect() but I kept getting the same error.
You can find my code on GitHub: https://github.com/almamarie/shoppingify-frontend in the backend-integration branch.
The target file is components/cart/completing-state/CompletingCarItem.tsx
I am new to react programming, and I have no idea how to set "incoming data" from a hyperlink on a web page when a user clicks a link an email.
In other words, I get an email with a link in it... I click on the link, that link takes me to a web page and populates two edit boxes with data (from the link).
I know how to code up the back end api that would accept data in api formate, for example in the 'discounts.js' api file, I could do this:
router.post('/discounts/:userCode/discount/:discountCode'
BUT what I want to do is send this link via email, have the user click the link and have the resulting page populated with data.
Here is an example link
example.com/discountPage/:snvpsnan8zosfluawpcn50ycdipa6rrqlym/code/:sdfiedgmmkfzuky2f6grds
So after the user clicks the link, the REACT web page edit boxes should look like this:
given the following react (partial) component:
class discountPage extends Component {
constructor() {
super();
this.state = {
userCode: '',
discountCode: ''
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
I am thinking I might be able to set the data in the componentDidMount - but really unsure of where the data from link comes from and how it gets set?
Does it come from the props ?
componentDidMount() {
console.log('Register : componentDidMount ');
this.setState({'userCode': this.props.userCode });
this.setState({'discountCode': this.props.discountCode });
}
UPDATE
Based on Pinaka30's response... I did some searching and found this:
https://www.webdeveloperpal.com/2018/02/21/react-router-get-url-params/
import queryString from 'query-string';
class UserComponent extends React.Component{
render(){
// url is 'https://www.example.com/user?id=123&type=4';
let url = this.props.location.search;
let params = queryString.parse(url);
console.log(params);
// The result will be like below
// { id: 123, type: 4 }
// other code
}
}
There can be many methods, and the one I am listing might not be the best, but it will definitely give you desired results.
Since you are clicking a link and then being redirected to a new page with your form, the request will be a GET request. As we know, the parameters are visible in the url in case of a GET request. So what you can do is retrieve userCode and DiscountCode from the url itself.
componentDidMount(){
var url = window.location.href; //Gives you the complete url
temp = url.split(""); //Split the url to retrieve both parameters according to your format
this.setState({
userCode: temp[0],
discountCode: temp[1]
});
}
In your render method, use state as the value
<input id="userCode" value={this.state.userCode} />
<input id="discountCode" value={this.state.discountCode} />
So as soon as your page loads and the component renders, componentDidMount will get called and update the states which will be reflected in your input boxes. Just split the url carefully. I didn't write that line completely because i didn't know the format.
It must be pretty regular issue.
I'm passing props down to the children and I'm using it there to request to the endpoint. More detailed: I'm clicking on the list item, I'm checking which item was clicked, I'm passing it to the child component and there basing on prop I passed I'd like to request certain data. All works fine and I'm getting what I need, but only for the first time, ie. when refreshing page incoming props are gone and I cannot construct proper URL where as a query I'd like to use the prop value. Is there a way to preserve the prop so when the page will be refresh it will preserve last prop.
Thank you!
(You might want to take a look at: https://github.com/rt2zz/redux-persist, it is one of my favorites)
Just like a normal web application if the user reloads the page you're going to have your code reloaded. The solution is you need to store the critical data somewhere other than the React state if you want it to survive.
Here's a "template" in pseudo code. I just used a "LocalStorage" class that doesn't exist. You could pick whatever method you wanted.
class Persist extends React.Component {
constuctor(props) {
this.state = {
criticalData = null
}
}
componentDidMount() {
//pseudo code
let criticalData = LocalStorage.get('criticalData')
this.setState({
criticalData: criticalData
})
}
_handleCriticalUpdate(update) {
const merge = {
...LocalStorage.get('criticalData')
...update
}
LocalStorage.put('criticalData', merge)
this.setState({
criticalData: merge
})
}
render() {
<div>
...
<button
onClick={e => {
let update = ...my business logic
this._handleCriticalUpdate(update) //instead of set state
}}
>
....
</div>
}
}
By offloading your critical data to a cookie or the local storage you are injecting persistence into the lifecycle of the component. This means when a user refreshes the page you keep your state.
I hope that helps!
I'm new in react and faced with the problem when tried to accomplish navigate through my api pages. What I've done: http://pastebin.com/hxf9PJ8k
It works perfectly on my opinion, but show only first api page. Links to all user profile works too, it was simple to do just adding an id to api link. So, my api returned to me objects that is actually users, and overall count of users in database and links to next page if exist or null and previous page or null. Now I cannot understand how to use those link to create 2 buttons — next and prev. How to pass whole link or just part next to page= to Users props and make xhr request.
Api example view:
count: 2302
next: "http://localhost:8080/instant/api/?page=2"
previous:
results:
0: Object
1: Object
2: Object
Thanks in advance!
Basically what suggest to yo to do is to create a currentPage variable which makes your logic very simple.
for previous and next buttons create a separate component to handle paging condition, handle any click event on the parent component to keep it simple.
class PrevBtn extends React.Component {
constructor(props){
super(props);
this.props.clickHandler = this.props.clickHandler.bind(this);
}
render() {
let button = null;
const {currentPage} = this.props;
if(currentPage>1){
button = <a onClick={this.props.clickHandler}>Prev</a>
}else{
button = <a disabled="disabled">Prev</a>
}
return(<div>{button}</div>)
}
}
I just did an example for you in codePen, but I just did the prev button logic, you can figure it out how to do the next button component.
I am trying to create a CanDeactivate guard, to prompt "save changes" to the user when he navigates away from the route. There are some routes that I would like to exclude (lets say when user switches tabs, but doesnt choose a new item). I've been really struggling in understanding how can I get the destination URL without using some sort of navigation service and just keep the full URL there. Here is my signature for can deactivate
// This is what handles the deactivate
public canDeactivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
All of the 'route' and 'state' object contain the previous URL and no information about the destination URL.
I trigger the navigation in another component with
this._router.navigate(['/clients', this.selectedClient.id, page]);
Actually destination state is one of the parameter of CanDeactivate.
canDeactivate(
component: CanComponentDeactivate,
route: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean {
return true;
}
Reference: https://angular.io/api/router/CanDeactivate
You can subscribe to the router's events:
NavigationStart should fire before CanDeactivate, so you can grab the destination.
routingDestination: string = "";
constructor(router:Router) {
router
.events
.filter(e:Event => e instanceof NavigationStart)
.subscribe((e: NavigationStart) => this.routingDestination = e.url)
}
}
That aside, I think needing to know the destination in CanDeactivate is kind of a design flaw. But as I don't know your app, this might actually be the right way.