Call model function from JavaScript in Laravel - javascript

I'm actually running into little problems with my current project. Following case:
I've got a model called "Posting" with relations:
public function subscribers(){
return $this->belongsToMany('User');
}
In my view-file there is a table containing all Postings and also a checkbox for subscribing/unsubscribing with the matching value to the posting-id:
<input class="click" type="checkbox" name="mobileos" value="{{{$posting->id}}}"
#if($posting->subscribers->find(Auth::User()->id))
checked="checked"
#endif
>
Now the thing I want to archive:
A JavaScript is going to watch if the checkbox is checked or not. According to that, the current user subscribes/unsubscribes to the posting. Something like:
$('.click').on('click',function() {
// $posting->find(---$(this).prop('checked')---)->subscribers()->attach(---Auth::user()->id---);
// $posting->find(---$(this).prop('checked')---)->subscribers()->detach(---Auth::user()->id---);
});
Is there any possibility to archieve that or any other ways? I couldn't get my head around this so far.
Cheers,
Chris

If you want to use Ajax to achieve this, you will need a REST endpoint in Laravel for the subscriptions, e.g.:
http://localhost/subscribe/{{userid}}
When this Endpoint is called, the database can be updated. The function could also return a JSON showing, if the saving database in the database successful.
Use this endpoint to make an Ajax Call on click:
var user = {
id: 0 // retrieve the correct ID from wherever it is stored
}
$('.click').on('click',function() {
$.GET('http://localhost/subscribe/' + user.id,
function () { // this is the success callback, that is called, if the Ajax GET did not return any errors
alert('You are subsribed')
});
});
Ideally you won't be using the GET method, but instead use POST and send the user ID as data. Also you would need to retrieve the user ID from session or wherever it is stored.
Take care that as you are using Ajax it can easily be manipulated from the client side. So on the server you should check, if the user ID that was sent is the same as in the Session. Maybe you don't need to send the user id at all, but that depends on how your backend is built.

Related

How do I pass a variable to JavaScript using Laravel in order to broadcast on a private channel?

I am building an app in Laravel 9.42.2 and have set up Laravel Echo and Soketi to broadcast events. I can successfully send and receive broadcasts on public channels, but I can't figure out how to broadcast on a private channel.
According to the docs I can do this with the example code below:
Echo.private(`orders.${orderId}`)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e.order);
});
What I don't understand is where the ${orderId} is passed to the JavaScript. I can create the private channel on the backend in PHP, but I don't know where the front end should be receiving the variables it needs to fill in the placeholders in the listener.
Options I have considered:
Query the database at the front of every response and send a list of all possible ID's back to the user to store for use as needed (i.e. get all orderId's related to the user as an array and use a loop to create a listener for each of them). I'm concerned this would add a lot of unnecessary trips to the database and overhead to the page load times for something that might not be needed.
Add a line in the Controller to parse the orderId to json just before calling the event dispatch. Not sure why this feels wrong, but it does.
You can do via this tricks.
The orderId can be a part of your page url or can be represented by a hidden element in your template, for example:
<input type="hidden" id="orderId" value="{{$orderId}}" />
In case you choose hidden element, just get its value and pass to the Echo.private() method.
var orderId = document.getElementById('orderId').value;
window.Echo.private(`orders.` + orderId)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e);
});

Can I do DOM manipulation within an Express POST request?

I'm working with basic HTML/CSS frontend, I currently have a landing page with a form on it that sends some data to a database. When the request is done, it is expecting some sort of response. In this case, I am re-rendering the page, however, I want to replace the form with some sort of a thank you message, something so the user knows that it has sent correctly. I have tried the solution of simply having a separate near identical page with the form removed and replaced, however, this kind of code cloning seems like an inefficient way to do it. Is there a way I could do some sort of front-end DOM manipulation from within my node app instead?
Generally, if you want to manipulate how the DOM looks server side you would need to render your entire page server side and then send it to the front end.
If you want to simply manipulate the DOM after a request is received on the front end, whic is a pretty regular practice for this type of stuff; regardless of the back end language(s) used, you can:
Submit form
Let user know form is submitting to server (Best practice for UX)
Once you receive your response, manipulate the DOM however you would like
For this use case, I've taken advantage of the async/await syntactical pattern which will allow you to wait for a response while not ending up in a nested callback pattern.
The attached snipped will fake a request to the server through a set timeout value, and echo what you put into the form back to the page. It's on a three second delay and uses AJAX to make the request.
*You can simplify this code by removing some logging and comments, but I've made it more verbose than necessary for learning purposes.
**I've purposely put the submit button outside of the form element so that it does not auto-post on submit. If you want to submit this way, you can use event.preventDefault() within the function, catch the event before it bubbles, and do this instead. Either way will work fine.
async function getDataAsync0(data) {
return new Promise(async (res) => {
setTimeout(()=>{
res(data);
},3000)
});
}
$(`#submitButton`).click(async () => {
// Create div to display what's going on
let statusAreaElement = $(`#statusArea`);
// Submit Event
statusAreaElement.html(`Submitted... Waiting for response...`);
// Cache input element
let inputElement = $(`#input01`);
// Cache form element
let formWrapperElement = $(`#formWrapper`);
// Cache success message div
let successMessageElement = $(`#successMessage`);
// Get value
let value = inputElement.val();
// Send value, await response;
let response = await getDataAsync0(value);
statusAreaElement.html(`Response returned -> ${response}`)
// Clear input element
inputElement.val(``);
// Hide form, show success message
formWrapperElement.hide();
successMessageElement.show();
})
#statusArea {
position: absolute;
left: 0;
bottom: 0;
}
#successMessage {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="formWrapper">
<form>
<label for="input01">Form Input</label>
<input id="input01" type="text">
</form>
<button id="submitButton">
Submit Form
</button>
</div>
<div id="successMessage">
Thanks for your submission!
</div>
<div id="statusArea">
</div>
JSFiddle offers an echo service so I've also written the same code into a fiddle so you can see it actually call the server and echo back the response.
Here is that link:
https://jsfiddle.net/stickmanray/ug3mvjq0/37/
This code pattern should be all you need for what you are trying to do. Again, this request is also over AJAX so the DOM does not need to completely reload; if you are actually going to be making a regular post (without AJAX) to the server and then reload the page afterwards, you can do the same thing - or simply construct the new page you wanted to send to them server side and then redirect them from there.
I hope this helps!
Can I do DOM manipulation within an Express POST request?
No. The server builds up a response (a big chunk of html), that gets sent to the client which parses it and builds up the DOM. You cannot directly work with that from the server.
However you can:
1) Modify the html the server sends (have a look at express.render)
2) Run a clientide script that opens a connection to the server (websockets, AJAX) and then mutate the DOM there when the server sends something.

Ajax inside wordpress security

Before I get to the question, let me explain how we have things set up.
We have a proxy.php file, in which class Proxy is defined with functions that call upon a rest for creating/editing/getting Wordpress posts, fields etc.
Then, we have a proxyhandler.php, in which Proxy class is initialized and serves as a handle between proxy.php and a javascript file.
In javascript file we have an ajax call to proxyhandler.php in which we send our secret and other data.
Now, the problem arises here:
We define the secret through wp_localize_script, by using md5 custom string + timestamp. We send the encripted string and timestamp through ajax to proxy handler, where we use the previous (hardcoded inside proxyhandler) string and timestamp to generate a md5 string again, and check the one sent against the one generated. If they are the same, we continue by doing whatever was requested, if they dont fit, we just return that the secret didn't match.
Now, the real issue comes here - by using wp_localize_script, the variable for the secret is global and as such, anyone can utilize it via dev tools and can send any ajax request to proxyhandler that they want.
What would be the proper procedure to make it more secure? We've thought of doing this:
Instead of using wp_localize_script, we put the script inside a php file, we define the secret using a php variable and then simply echo the secret file into ajax. Would this be viable, or are there any other ways?
Instead of sending an encrypted string in global scope, then check against it, you should use nonce in your AJAX request:
var data = {
action: 'your_action',
whatever_data: who_know,
_ajax_nonce: <?= wp_create_nonce('your_ajax_nonce') ?>
};
Then, use check_ajax_refer() to verify that nonce:
function your_callback_function()
{
// Make sure to verify nonce
check_ajax_refer('your_ajax_nonce');
// If logged in user, make sure to check capabilities.
if ( current_user_can($capability) ) {
// Process data.
} else {
// Do something else.
}
...
}
Depend on the AJAX METHOD, you can use $_METHOD['whatever_data'] to retrieve who_know data without needing to use wp_localize_script().
Also remember that we can allow only logged in users process AJAX data:
// For logged in users
add_action('wp_ajax_your_action', 'your_callback_function');
// Remove for none logged in users
// add_action('wp_ajax_nopriv_your_action', 'your_callback_function');
The final thing is to make sure NONCE_KEY and NONCE_SALT in your wp-config.php are secure.

Updating total number on website with jQuery / Javascript?

This below is displaying Total racers on my website but its not updating live. I need to referesh the page to grab the new number from the database, so what's the simple way of updating it live with jquery/javascript without refreshing the page? Thanks a lot for taking the time to check my question and possibly answer.
<div id="stats">
<div id="racers">
<span><?=number_format($racers, 0, ' ', ' ')?></span>
RACERS
</div>
</div>
Jquery Ajax:
$.post('page.php', {
postVariable : value
}, function(data) {
//do something with data retrieved from php script
});
You set 'page.php' to a script that gets the data you want and echoes it.
You then retrieve what was echoed in the callback function(data);
So data will be the variable containing the value you need. You put this script in a
javascript function and call it when you need to make a request for information on the back-end.
If you have questions let me know. If you need more information on the ajax request you can find it here as well: api.jquery.com/jquery.post/
What you need to do this is the following:
1. Have an action in a controller that outputs the total number of racers
For example:
class Data extends CI_Controller {
public function GetTotalRacers() {
// This is dummy data. You need to replace this code with the correct
// number of racers retrieved from the database
echo 14;
}
}
Take note of where this action is. I'm assuming codeigniter will make the path something like /Data/GetTotalRacers in this case (that depends on how your route rules are configured).
2. Use JavaScript to ask the server for the data and display the result on the page
I recommend you have a method that runs every X number of seconds to refresh the total number of racers. To achieve this, you can use setInterval. Within the setInterval's function have an ajax call to your action. Finally, display the value that's returned from the server:
setInterval(function() {
$.ajax({
// Replace the url value with the correct url to access your action
url: '/Data/GetTotalRacers',
cache: false
})
.done(function( totalRacers ) {
$("#racers span").text(totalRacers);
});
}, 60000); // ex. Update every 60000ms
Note: I've never used codeigniter, but hopefully this description will help set you on the right path.

Recommended way to redirect to same view and perform server side code from a client side event in MVC

I am having a hard time deciding on an appropriate way to Perform some server side functionality and then redirecting to the same View in my ASP.Net MVC project.
I am trying to call an Action after the selected index changed client side event of my combobox.
One way I can think of is to change the window.location to the url of my Action and pass the data i need via the query string like this
function SelectedIndexChanged(s,e)
{
window.location.href = "/MyController/MyAction?" + s.GetValue();
}
I also see lots of people saying you should use jquery ajax for this
function SelectedIndexChanged(s,e)
{
$.ajax({
url: 'MyController/MyAction',
data: { value: s.GetValue() },
success: function(){
alert('Added');
}
});
}
My Action looks something like this where i set some cookie values using the value and Set View bags values depending on the selected index.
public ActionResult SelectedIndexChanged(string value)
{
//Do some processing
//Set cookie values
SetViewBags(value);
return Redirect(Request.UrlReferrer.ToString());
}
Is there a better approach to accomplish my task, I am leaning more towards changing the location.href as it is simpler, but i'm not sure if this is good practice?
EDIT
To Clarify this Combobox is a Devexpress MVC extension so I will have to handle the "SelectedIndexChanged" client side event.
This Combobox is also on my layout page so it appears on every view in my project. So when it is changed i will need to to call the same Action no matter what page it is on
As you've indicated that your form is in your layout (not a view), I recommend you look at using a view partial. Fortunately, MVC has already provided an example with their view partial (can't remember the name) that has the login and logout buttons. If a user clicks logout, some javascript is fired and the form is submitted. This will redirect the user; however, you could also send the original address (referrer) as a parameter to your server method and then redirect to that page afterward.
You could always use an Html.Action
function SelectedIndexChanged(s,e)
{
#Html.Action("ActionName", "ControllerName", {optional route values})
}

Categories