Here products state is null when I try to display the product. I know to handle this we can use useEffect again for displaying the product but still product state is null. Here is the part of the code that I tried to attempt.
function Product() {
const [products, setProducts] = useState(null);
useEffect(() => {
axios
.get("http://localhost:4000/products")
.then((res) => setProducts(res.data));
}, []);
useEffect(() => {
console.log(products); // Here still products is null
products.map((product) => (
<tr key={product.id}>
<td>{product.productName}</td>
<td>{product.productDesc}</td>
<td>{product.manufacturer}</td>
<td>{product.price}</td>
<td>{product.quantity}</td>
</tr>
));
}, [products]);
return <></>;
}
If I remove products.map then it is showing as two values first one is null and the second is an array of the object (i.e my data).
Right now, nothing will ever be rendered as the return is empty (almost).
Try
function Product() {
const [products, setProducts] = useState(null);
useEffect(() => {
axios
.get("http://localhost:4000/products")
.then((res) => setProducts(res.data));
}, []);
if (!products) {
return null;
}
return products.map(product => (
<tr key={product.id}>
<td>{product.productName}</td>
<td>{product.productDesc}</td>
<td>{product.manufacturer}</td>
<td>{product.price}</td>
<td>{product.quantity}</td>
</tr>
));
}
This is a typical example of lifting the state up to the higher-order component in React.js.
All states and API calls need to be written in your top-level-component.
import ProductItem from "./ProductItem";
function Product(){
const [products, setProducts] = useState(null);
useEffect(() => {
axios
.get("http://localhost:4000/products")
.then((res) => setProducts(res.data));
}, []);
return(
<table>
<thead>
<th>Name</th>
<th>Description</th>
<th>Manufacturer</th>
<th>Price</th>
<th>Qunatity</th>
</thead>
<tbody>
<ProductItem products={products} />
</thead>
</table>
);
}
Here, the products state is passed as a prop to ProductItem. Now the ProductItem component will have the list of the product's item which can be accessed as a prop.
function ProductItem({products}) {
useEffect(() => {
console.log(products); // getting the list of the product in the developer console,
}, [products]);
return (
<>
{products.map((product) => (
<tr key={product.id}>
<td>{product.productName}</td>
<td>{product.productDesc}</td>
<td>{product.manufacturer}</td>
<td>{product.price}</td>
<td>{product.quantity}</td>
</tr>
))}
</>;
);
}
export default ProductItem;
Related
I have an observable that fills a table like this:
<table class="table table-borderless" style="width:44%;" *ngIf="(borrowers_main_data$ | async) as borrowers_main_data">
<tbody>
<tr>
<td width="8%">CDI:</td>
<td>
<strong>{{ borrowers_main_data.Cdi }}</strong>
And this is the code that fills the table:
public borrowers_main_data$ = this.service.cdiVariable$.pipe(
switchMap(cdiVariable => {return this.dataSource.getCustomer(cdiVariable).pipe(
catchError(error => {
if (error.error instanceof ErrorEvent) {
this.errorMsg = `Error: ${error.error.message}`;
} else {
this.errorMsg = `Error: ${error.message}`;
}
return of({} as Customer);
}))
}));
The problem is that in the case of a second search (after a successful one) that returns the Observable of the empty object the table stays populated with the previous data.
Is-it possible to add "Column Search" with infyom laravel-generator yajra datatable.
I change tables_searchable_default from false to true
form this doc https://www.infyom.com/open-source/laravelgenerator/docs/8.0/configuration#options
But It does not change anything ...
Does so has a solution?
Thank in advance.
My answer on Infyom Gihthub
https://github.com/InfyOmLabs/laravel-generator/issues/972
How I did it (with a little modification in yajra/datables-html/builler - see Step 5)
0-https://datatables.net/examples/api/multi_filter.html
◦ reference example
1-php artisan infyom.publish:templates
2-resources/infyom/infyom-generator-templates/scaffold/views/datatable_body.stub
datatable_body.stub
#section('third_party_stylesheets')
#include('layouts.datatables_css')
#endsection
{{-- $dataTable->table(['width' => '100%', 'class' => 'table table-striped table-bordered']) --}}
{!! $dataTable->table(['width' => '100%', 'class' => 'table table-striped table-bordered'],true) !!} {{-- drawFooter --}}
3 config/datatables-html.php
'datatables::script',
'script' => 'layouts/script',
];
4 resources/views/layouts/script.blade.php
$(document).ready(function() {
// Setup - add a text input to each footer cell
$("#dataTableBuilder tfoot th").each( function () {
var title = $(this).text();
$(this).html( "" );
} );
});
$(function(){window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}=window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}||{};window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"]=$("#%1$s").DataTable(%2$s
,initComplete: function () {
// Apply the search
this.api().columns().every( function () {
var that = this;
$( "input", this.footer() ).on( "keyup change clear", function () {
if ( that.search() !== this.value ) {
that
.search( this.value )
.draw();
}
} );
} );
}
} ); }
);
5 • vendor/yajra/laravel-datatables-html/src/Html/Builder.php
public function generateScripts()
{
$parameters = $this->generateJson();
$parameters=substr($parameters,0,strlen($parameters)-1); # remove the last } in order to add a parameter
return new HtmlString(
sprintf($this->template(), $this->getTableAttribute('id'), $parameters)
);
}
when I try to create a new subscription I get this error (This customer has no attached payment source or default payment method. ) so I checked the PaymentController with dd($paymentMethod) which returned null
so I don't know why the variable $paymentMethod in store method is returning NULL from the $request but the request, for the price is returning the price_id. Please any help is appreciated
but when console.log() setupIntent.payment_method it returned the payment_method in the console
Here is my PaymentController
public function index()
{
$availablePlans = [
'price_1HnIiLLzAo4pwMcyh2aGaznB' => 'Monthly',
'price_1HnJ2vLzAo4pwMcygQT66juk' => 'Yearly',
'price_1HnIhILzAo4pwMcy9iH3j30L' => 'Free Membership'
];
$user = auth()->user();
$data = [
'intent' => $user->createSetupIntent(),
'plans' => $availablePlans
];
return view('payments.checkout')->with($data);
}
public function store(Request $request)
{
$user = auth()->user();
$paymentMethod = $request->payment_method;
// dd($paymentMethod);
$planId = $request->plan;
$user->newSubscription('premium', $planId)->create($paymentMethod);
return response(['status' => 'success']);
}
This is the Javascript
window.addEventListener('load', function (){
// Create a Stripe client.
const stripe = Stripe('pk_test_51H2OqqLzAo4pwMcyT4h405wpFRAn3FWhvByfvmVnW6tabrIsDoU1dBXJ0UaWexUJeacCJ9uKpb5OBmmA2KaCg4sd00ZZ5tj2q8');
// Create an instance of Elements.
const elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
// const cardElement = elements.create('card', {style: style});
// Create an instance of the card Element.
const cardElement = elements.create('card');
// Add an instance of the card Element into the `card-element` <div>.
cardElement.mount('#card-element');
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;
const plan = document.getElementById('subscription-plan').value;
cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.handleCardSetup(
clientSecret, cardElement, {
payment_method_data: {
billing_details: { name: cardHolderName.value }
}
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
// console.log('handling success', setupIntent.payment_method);
axios.post('/subscribe', {
payment_method: setupIntent.payment_method,
plan: plan
})
}
});
});
Here is the form
<form action="{{ route('subscribe')}}" method="POST" id="">
#csrf
<div class="form-content">
<div class="field">
<select class="form-control" name="plan" id="subscription-plan">
#foreach ($plans as $key=>$plan )
<option value="{{$key}}">{{$plan}}</option>
#endforeach
</select>
</div>
<div class="field">
<input type="text" autocorrect="off" spellcheck="false" id="card-holder-name" maxlength="25" />
<span class="focus-bar"></span>
<label for="cardholder">Card holder (Name on card)</label>
</div>
<div class="field mb-5" id="card-element">
<!-- Stripe Elements Placeholder -->
</div>
<button id="card-button" data-secret="{{ $intent->client_secret }}"><span>Pay</span></button>
</div>
</form>
The Route
Route::resource('payments', 'PaymentsController', [
'names'=> [
'index' => 'checkout',
'store' => 'subscribe',
]
]);
Looks like there is something wrong with how you're using axios. Have you tried taking a look at laravel simple axios with argument
Adding a hidden input field in the form and setting the value to setupIntent.payment_method passed the payment_method id to the controller which is used to create the subscription so the problem is solved.
A few modifications and adding a hidden input field to the JS
// Handle form submission.
var form = document.getElementById('payment-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
//cardButton.addEventListener('click', async (e) => {
//e.preventDefault()
const { setupIntent, error } = await stripe.handleCardSetup(
clientSecret, cardElement, {
payment_method_data: {
billing_details: { name: cardHolderName.value }
}
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
//console.log('handling success', setupIntent.payment_method);
axios.post('/subscribe',{
plan : plan
})
var paymentMethod = setupIntent.payment_method;
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'payment_method');
hiddenInput.setAttribute('value', paymentMethod);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
I am using vuejs with laravel and I have links for next and previous pages while url is changing but new data won't show.
Code
Controller
$verse = Chapter::where('slug', $slug)->with(['verses', 'book'])->first();
$next = Chapter::where('id', '>', $verse->id)->first();
$previous = Chapter::where('id', '<', $verse->id)->first();
return response()->json([
'verses' => $verse,
'next' => $next,
'previous' => $previous,
]);
component
<div v-if="previous !== null" :v-model="previous" class="bible-nav-button previous">
<router-link :to="`/${testament_slug}/${book_slug}/${previous.slug}`">
<i class="fas fa-chevron-left"></i> <span>Previous</span>
</router-link>
</div>
<div v-if="next !== null" :v-model="next" class="bible-nav-button next">
<router-link :to="`/${testament_slug}/${book_slug}/${next.slug}`">
<span>Next</span> <i class="fas fa-chevron-right"></i>
</router-link>
</div>
<script>
export default {
name: "books",
data() {
return {
url: window.location.origin + "" + window.location.pathname,
title: '',
testament_slug:'',
book_slug: '',
slug: '',
verses: [],
next: '',
previous: ''
}
},
methods: {
getBooks: function(){
this.testament_slug = this.$route.params.testament_slug
this.book_slug = this.$route.params.book_slug
this.slug = this.$route.params.slug
axios.get('/api/'+this.$route.params.book_slug+'/'+this.$route.params.slug+'/'+this.$route.params.slug).then((res) => {
this.verses = res.data.verses
this.title = "Read Bible: " +res.data.verses.book.name+ " " +res.data.verses.name
this.next = res.data.next
this.previous= res.data.previous
})
.catch((err) => {
console.log(err)
});
},
myHTML: function(item) {
return "<strong>"+item.number+"</strong> "+item.body+" ";
}
},
mounted() {
this.getBooks();
}
}
</script>
Any idea how i can fetch my new data?
You can use :key props in <router-view> tag and use the route fullpath.
<router-view :key="$route.fullPath"></router-view>
I used to put a watcher of the current route and call function to fetch data, but I just found that we can do this after watching vue-router tutorial from vueschool.
Also see the answer of this question
You have two simple options:
1) Change the "previous" and "next" to #click actions that call the fetch function again and then update the URL (like this this.$router.push()).
<span #click="goNext(/* needed arguments here */)">Next</span>
goNext (/* params here */) {
//set whatever variables you need to
this.$router.push(/* route as string here */)
this.getBooks()
}
2) Since you're using the router, use guards to update every time the URL changes:
https://router.vuejs.org/guide/advanced/navigation-guards.html
beforeRouteUpdate(to, from, next) {
this.getBooks()
next()
}
I am trying to bind the data from PHP API to the client (Angular 2), however, it didn't work as expected. Any idea?
This is the laravel API code below,
return response()-> json('message',200);
This is the Angular 2 service and subscribe as below,
getString(): Observable<string> {
return this._http.get(this.api_misc_url)
.map((response: Response) => <string>response.json())
.catch(this.handleError);
}
This is the subscriber code as below,
public ngOnInit(): void {
this.chartId = `mydash-chart-${MydashChartComponent.currentId++}`;
this.laravelApiService.getString().subscribe(
messageFromLaravelApi => this.MessageFromLaravelApi = <string>messageFromLaravelApi,
error => this.errorMessage = <string>error);
}
This is the UI binding code below,
<div class='panel-heading' >
<h2>Charting </h2>
<td>{{ MessageFromLaravelApi }}</td>
</div>
But, I can see value shown on the console log.
Either use subscribe or async , not both. async takes an observable or promise and renders data .
Either this
this.MessageFromLaravelApi$ = this.laravelApiService.getString();
http :
<tr *ngFor="let message of MessageFromLaravelApi$ | async">
<td>{{ message }}</td>
</tr>
OR
this.laravelApiService.getString()
.subscribe(
messageFromLaravelApi =>
this.MessageFromLaravelApi = messageFromLaravelApi,
error => this.errorMessage = <any>error
);
http
<tr *ngFor="let message of MessageFromLaravelApi">
<td>{{ message }}</td>
</tr>
Updating the same code :
Service code
getString(): Observable<string> {
return this._http.get(this.api_misc_url)
.map((response: Response) => response.json())
.catch(err=> console.error(err));
}
Component Code :
public ngOnInit(): void {
this.chartId = `mydash-chart-${MydashChartComponent.currentId++}`;
this.laravelApiService.getString().subscribe(
messageFromLaravelApi =>
this.MessageFromLaravelApi = messageFromLaravelApi,
error => this.errorMessage = error);
}
HTML
<div class='panel-heading' >
<h2>Charting </h2>
<td>{{ MessageFromLaravelApi }}</td>
</div>