I started messing around with Vue.js earlier this week.
So far I created a list of MTG(a TCG) cards. The data comes from the database through an Ajax request. This all works like a charm.
What i want to do next is replace the string that contains the costs of a card e.g. something like '{1}{U}{G}' with images for the corresponding tag.
HTML:
<div v-for="(cards, key) in mainBoard" class="">
<table class="table">
<tr>
<th colspan="5">#{{ key }}</th>
</tr>
<tr>
<th>#</th>
<th>Name</th>
<th>ManaCost</th>
#if($deck->enableCommander())
<th>Commander</th>
#else
<th></th>
#endif
<th>Actions</th>
</tr>
<tr v-for="card in cards">
<td>#{{card.pivot.quantity}}</td>
<td>#{{card.name}}</td>s
<td v-html="replaceManaSymbols(card)"></td>
#if($deck->enableCommander())
<td>
<span v-if="card.pivot.commander" #click="preformMethod(card, 'removeCommander', $event)"><i class="fa fa-flag"></i></span>
<span v-else #click="preformMethod(card,'assignCommander', $event)"><i class="far fa-flag"></i></span>
</td>
#else
<td> </td>
#endif
<td>
<button #click="preformMethod(card,'removeCardFromDeck', $event)"><i class="fa fa-times-circle"></i></button>
<button #click="preformMethod(card,'plusCardInDeck', $event)"><i class="fa fa-plus-circle"></i></button>
<button #click="preformMethod(card,'minusCardInDeck', $event)"><i class="fa fa-minus-circle"></i></button>
</td>
</tr>
</table>
</div>
Vue.js
new Vue({
el: '#Itemlist',
data: {
mainBoard: [],
sideBoard: [],
},
methods:{
preformMethod(card, url){
var self = this;
var varData = {
slug: '{{ $deck->slug }}',
card: card.id,
board: card.pivot.mainboard
};
$.ajax({
url: '/vue/'+url,
data: varData,
method: 'GET',
success: function (data) {
self.mainBoard = data.mainBoard;
self.sideBoard = data.sideBoard;
},
error: function (error) {
console.log(error);
}
});
},
replaceManaSymbols(card){
var mc = card.manaCost;
var dump = mc.replace(/([}])/g, '},').split(',');
var html = '';
/**
* replace each tag with an image
*/
return html;
}
},
mounted(){
var self = this;
var varData = {
slug: '{{ $deck->slug }}'
};
$.ajax({
url: '/vue/getDeckList',
data: varData,
method: 'GET',
success: function (data) {
self.mainBoard = data.mainBoard;
self.sideBoard = data.sideBoard;
},
error: function (error) {
console.log(error);
}
});
}
})
I pass the card as a parameter to the replaceManaSymbols method. I can console.log the contents of mana without any issue. But as soon as a want to modify the string Vue throws the error TypeError: Cannot read property 'toLowerCase/split/replace' of null. I'm not really sure what's going wrong. Any idea's?
As a rule of thumb, you shouldn't use methods on the display side. Keep them for the update side - processing changes back into a store and such. Methods aren't reactive - they need to be called. You want your display to automatically reflect some underlying data, so you should use computed.
You should also avoid using v-html, because you end up with markup outside your templates, and that markup is static. It's not totally clear to me what will be in v-html, but you should try and keep markup in your template, and inject values using data, props or computed. Hope this helps!
If you want a div with some text that magically turns into an image tag, this could be a good use for <component :is>.
Related
I'm just trying to send the editable table row data to the controller onClick of the Save button, update that data in the database, and return success.
But I cannot display the data inside the controller function of laravel. Data inside saveMe function is coming as desired as shown in below screenshot but it is not going to the controller
<table id="customersTable" class="table table-bordered table-responsive-md table-striped text-center" style="border-style: solid; border-color:red">
#php
$customersData = Session::get('data');
$issues = Session::get('issues');
#endphp
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Contact</th>
<th>Address</th>
<th>Name</th>
</tr>
</thead>
<tbody id="bodyData">
#foreach ($customersData as $key => $data)
<form action="ajaxform">
<!-- This is our clonable table line -->
<tr>
<td>{{$key}}</td>
<td name="name" class="pt-3-half name" contenteditable="true"
value={{$data['name']}} data-id={{$key}}>
{{$data['name']}}
</td>
<td name="email" class="pt-3-half email" contenteditable="true"
value={{$data['name']}} data-id={{$key}}>
{{$data['email']}}
</td>
<td>
<div class="test">
<span class="table-save">
<button type="button" onclick="saveMe(this)" class=" btn btn-secondary btn-rounded btn-sm my-0 saveBtn">
Save
</button>
</span>
</div>
</td>
</tr>
</form>
#endforeach
</tbody>
</table>
JavaScript function
<script>
function saveMe(params) {
var tr = $(this).closest("tr"); //get the parent tr
var name = $(params).closest("tr").find(".name").text();
var email = $(params).closest("tr").find(".email").text();
console.log(name);
console.log(email);
$.ajax({
url: '/customers/saveSingleRecord',
type: 'GET',
data: {
_token:'{{ csrf_token() }}',
value: {
'name' : name,
'email' : email,
'contact' : contact,
'address' : address,
},
},
success: function(data){
alert("success");
}
});
}
Function inside the controller
class CustomersController extends Controller
{
public function saveSingleRecord(Request $request)
{
// $name = $_GET['name'];
$name = $request->name;
dd($name); // <------------------ Not showing anything
// return response()->json($name);
}
}
Route inside web.php
Route::post('/customers/saveSingleRecord/', [CustomersController::class, 'saveSingleRecord']);
In your ajax request you are passing your data inside value attribute so it's not showing. If you try $request->value['name'] then it will show you the name. If you want to get name directly in request object then pass as like below.
$.ajax({
url: '/customers/saveSingleRecord',
type: 'GET',
data: {
_token:'{{ csrf_token() }}',
'name' : name,
'email' : email,
'contact' : contact,
'address' : address,
},
success: function(data){
alert("success");
}
});
The correct way to send ajax is below
$.ajax({
url: '/customers/saveSingleRecord',
type: 'GET',
data: {
name : name,
email : email,
contact : contact,
address : address,
_token :'{{ csrf_token() }}',
},
success: function(data){
alert("success");
}
});
Basically you set key value pair within data.
So the situation is such:
I am using data-tables in my .cshtml file. I have managed to add records via a modal but the issue is when i want to populate a modal in order to edit the data from a row. I do not wish to fetch data from the row but instead do a Ajax request to fetch the data. Below shows the structure of my table
<table id="example" class="table table-striped table-bordered dt-responsive display nowrap" cellspacing="0">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Email</th>
<th>Status</th>
<th>Roles</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model.Users)
{
<tr>
<td>#user.FirstName</td>
<td>#user.LastName</td>
<td>#user.UserName</td>
<td>#user.Email</td>
<td>#user.status</td>
<td>
#{ if (user.Roles.Contains("SuperAdmin"))
{
<span class="badge badge-danger">SA</span> }
else if (user.Roles.Contains("Admin"))
{
<span class="badge badge-danger">ADMIN</span> }
else if (user.Roles.Contains("Moderator"))
{
<span class="badge badge-warning">MOD</span> }
else if (user.Roles.Contains("Basic"))
{
<span class="badge badge-success">BASIC</span> }
}
</td>
<td>
#{ if (user.Roles.Contains("SuperAdmin"))
{
<span class="badge badge-warning">Locked</span> }
else
{
<button class="btn btn-sm btn-dark details" id="useredit" data-id="#user.UserId">Edit</button>
<a class="btn btn-primary btn-sm" asp-area="Identity" asp-page="/Account/UserRoles" asp-route-userId="#user.UserId">Manage Roles</a> }
}
</td>
</tr>}
</tbody>
</table>
When i click on the edit button the follow code gets executed
$("button.details").on('click', function () {
console.log({ "id": $(this).attr("data-id") });
var userid = $(this).attr("data-id");
$.ajax({
type: "POST",
url: "/Identity/Account/Users?handler=UsersAsJson",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: { id:userid },
contentType: "json; charset=utf-8",
success: function (regions) {
console.log(regions)
},
failure: function (response) {
alert(response);
}
});
});
And this is the handler function below
public async Task<IActionResult> OnPostUsersAsJsonAsync(string? id)
{
System.Diagnostics.Debug.WriteLine("id passed",id);
return new JsonResult(id);
}
Can anyone tell me how do we pass the id from the ajax request into the handler function? cause at the moment its not posting to the OnPostUsersAsJsonAsync function.
Also note i have tried getJSON without any success.
For you do not have a form,be sure you have added token like below:
<button class="btn btn-sm btn-dark details" id="useredit" data-id="#user.UserId">Edit</button>
#Html.AntiForgeryToken()
Change your js like below:
#section Scripts
{
<script>
$("button.details").on('click', function () {
console.log({ "id": $(this).attr("data-id") });
var userid = $(this).attr("data-id");
$.ajax({
type: "POST",
url: "/Identity/Account/Users?handler=UsersAsJson",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: { id: userid },
//contentType: "json; charset=utf-8", //remove this line
success: function (regions) {
console.log(regions)
},
failure: function (response) {
alert(response);
}
});
});
</script>
}
Startup.cs:
services.AddRazorPages();
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN"); //be sure add this line
Result:
<script>
export default {
name: "OutPatient",
data(){
return{
out_patients: {}
}
},
methods: {
index(){
axios.get('/data/out_patient').then(({data}) =>
(this.out_patients = data.data));
},
update(){}
},
created(){
this.index();
}
}
</script>
<tr v-for="out_patient in out_patients" v-bind:key="out_patient.id">
<td>{{out_patient.id}}</td>
<td>{{out_patient.first_name}}</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>
<i class="fa fa-edit blue"></i>
|
<i class="fa fa-trash red"></i>
</td>
</tr>
This is my code but the data is not showing in the table even though in the XHR the data shows there.
In the inspect element I can see the data but the v-for loop is unable to display the data.
Seems to me like you tried to extract data twice, you have this:
axios.get('/data/out_patient').then(({data}) =>
(this.out_patients = data.data));
if you already extract it here: {data} then you don't need data.data, only data below?
index() {
this.error = this.out_patients = null;
this.loading = true;
axios
.get('/data/out_patient')
.then(response => {
this.loading = false;
this.out_patients = response.data;
}).catch(error => {
this.loading = false;
this.error = error.response.data.message || error.message;
});
},
this rather works for me.
thank you all for the support
can you try fetching the data on mounted life cycle hook instead of created in order to populate the table with data on page load mounted is the best hook lifecycle as much I know.
<script>
export default {
name: "OutPatient",
data(){
return{
out_patients: {},
out_patient:'',
}
},
methods: {
index(){
axios.get('/data/out_patient')
.then(({data}) =>
(this.out_patients = data.data));
},
update(){
}
},
created(){
this.index();
}
}
</script>
<tr v-for="out_patient in out_patients" v-bind:key="out_patient.id">
<td>{{out_patient.id}}</td>
<td>{{out_patient.first_name}}</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>
<a href="#">
<i class="fa fa-edit blue"></i>
</a>
|
<a href="#">
<i class="fa fa-trash red"></i>
</a>
</td>
</tr>
Just declare out_patient in data. I hope this solves your issue.
And also check if out_patients is returning data.
I want to pass data from AJAX call.Data wants to be the (form input data+key).
When i pass the data it returns the data that i want.But it also returns a None type value.
I want to get rid of that None type value.
Following shows my form template code.
<form action="/seq_input/" method="POST" id="MyForm"><br>
<p style="color:black;font-size:14px">These messages haven't reciever.</p>
<p style="color:black;font-size:14px">If you want you can add recivers</p>
<table id="tb1">
<tr>
<th style="display:none;">Key</th>
<th>Message</th>
<th>Reciver</th>
</tr>
{% for key,values in NullList.items%}
<tr>
<td style="display:none;">{{key}}</td>
<td>{{values}}</td>
<td><input type="text" id="{{key}}" name={{key}} value=""></td>
</tr>
{% endfor %}
</table>
<br>
<input type="submit" value="SubmitMyInputs" onclick="get_details()">
</form>
following shows the Ajax call.
var jsonArr = [];
function get_details(){
console.log("submit");
console.log(myObject);
for(var value in myObject){
var x=document.getElementById(myObject[value]).value;
jsonArr.push({
key:myObject[value],
reciever:x
});
}
alert(JSON.stringify(jsonArr));
get_ajax(jsonArr);
}
function get_ajax(jsonArr){
$.ajax({
method: 'POST',
url: $('#MyForm').attr('action'),
data: {'data': JSON.stringify(jsonArr)},
success: function(response) {
console.log(response)
alert('success');
},
error: function(response) {
console.error(response)
alert('error');
}
});
}
Following has my .py file code.
def get_seq_input(request):
if request.method == 'POST':
message = request.POST.get('data')
print(message)
the result is
[{"key":1,"reciever":"system"}] and
None
anyone have idea to getrid of this None?
I have a design of grid in controller that displays me all data of selected check boxes.
This grid gets appended to a span through ajax.
While performing a delete request, one by one my data in grid gets deleted,
but the grid header stays as it is.
This is my design of grid in controller:
$res_div = '';
$res_div.='<table width="100%" border="0" class="table table-striped table-bordered table-hover">';
$res_div.='<tr>
<th width="100%">SublawId</th>
<th width="100%">Sublawname</th>
<th width="100%">View</th>
<th width="100%">Update</th>
</tr>';
foreach ($law as $sublaw)
{
$law_details = DB::table('tbl_law_sub_master')->where('id', $sublaw->id)->select('*')->first();
$res_div.='<tr>
<td>
<strong>'.$law_details->lms_id.'</strong>
</td>
<td>
<strong>('.$law_details->sub_law_name.')</strong>
</td>
<td align="center">
<input type="checkbox" id="cb1" onclick="ts(this)" class="cb1" name="viewsub_'.$sublaw->id.'">
</td>
<td align="center">
<input type="checkbox" id="cb1" onclick="ts(this)" class="cb1" name="updatesub_'.$sublaw->id.'">
</td>
</tr>';
}
$res_div.='</table>';
$data=array(
'res_div'=>$res_div,
'law'=>$law
);
return json_encode($data);
my ajax request on blade:
$.ajax({
url: "{{ URL::to('staff/staffpostsublawsdata') }}?sub_law_id="+sublaw_ids.join(),
type: 'POST',
dataType: "json",
data: formData,
async: false,
cache: false,
contentType: false,
processData: false,
success: function (returndata) {
var res_sublaw_content=returndata.res_div;
var data = document.getElementById("append_sublaw_grid").innerHTML = ""; $('#append_sublaw_grid').append(res_sublaw_content);
return false;
}
});
On deletion all data gets deleted one by one from grid, but its header stays..
A screenshot:
Everytime you remove a row u can count the number of rows left using
var rowCount = $('.table tbody tr').length;
if rowcount goes to 0 then just hide the table using
$('.table').hide()
Working example:
Put this code in the function where you delete the rows
var rowCount = $('.table tbody tr').length;
if( rowcount == 0){
$('.table').hide();
}