Ajax and Mongodb, use _id - javascript

I have a test project using express.js that displays all items in a mongo database on a webpage. Each database entry is displayed on the page with a button to delete it.
-each i in docs
p ----------------------
p <strong>Name: #{i.name}
p <strong>Type: #{i.type}
p <strong>Amount: #{i.quantity}
p <strong>ID: #{i._id}
input(type = 'button', value ="delete item", id='delete')
I want the button to send a DELETE request to /api/item/_id
My script is as follows
script(type='text/javascript').
$(document).ready(function() {
$("#delete").click(function() {
$.ajax({
type: 'DELETE',
url: '/api/item/' + this._id
}).done(function(result) {
});
});
});
This is not sending the desired request. How would I go about passing the _id from the item to the button?
If I set the URL to a know _id, like below, it works and the item is deleted
url: '/api/item/56f3e800d6f24d0819e43fcc'
Thanks in advace

Use data- attribute
Html
<input type="button" id="delete" data-id="mongo id here" />
JS
$.ajax({
type: 'DELETE',
url: '/api/item/' + this.attr('data-id')
})
Also you'd better use class instead of id="delete"

If I understand your looping code you appear to be assigning the same HTML ID attribute to each button:
input(type = 'button', value ="delete item", id='delete')
That makes for invalid HTML (only one item can have a given ID). You can make the delete attribute a class where its legal to have more than one item with the same class.
If you console.log(this) when any of these buttons are clicked what is this referring to? What _id do you get? Do you get the same _id regardless of what button is clicked?

Related

How do I pass reference of the p tag when ever the button is clicked?

This is how i have created the button
<button type="submit" id="likebtn" onclick="likedpost(this) " data-postid="<%=blog._id%>" data-author="<%=user.username%>">Like</button>
<span ><p id="likescounter"><%=blog.likes%> </p></span> // I want to pass the reference of this p (id) when clicked the above button
This is my liked post function-
function likedpost(el)
{
var id = el.dataset.postid;
var author = el.dataset.author;
console.log("id form likedpost function =" +id+"and author of this post is="+author);
console.log('post liked');
var request = $.ajax({
type: "POST",
url: "api/index/like",
data: {id: id, author:author},
async:false,
dataType:"html",
success: function(data){
findingnumberoflikes(data);
console.log("action performed successfully")
},
error: function(){
console.log("error occured");
}
});
}
function findingnumberoflikes(data)
{
console.log("the data returned is "+ data);
$(#likescounter).html(data); // here I can not select the likescounter id
console.log("likes counter updated");
}
Basically, I want to select the respective p with jquery's $ selector and update its data but it is giving me private identifiers are not allowed outside class bodies error.
How can I do that. Thank you!
There is a list of above buttons and p tag are for every blog post in the databse. Sorry! earlier I couldn't frame my question better.
Although we can do this with sibling selector etc.. I suggest you to arrange this differently for example,
<span ><p id="likescounter"><%=blog.likes%> </p></span>
in this line, change id="likescounter" to something that would give likescounter+blogid
something that would replace like the following
<span ><p id="likescounter-<%=blog._id%>"><%=blog.likes%> </p></span>
you wanna get "id=likescounter-1" for blog id 1, id="likescounter-2" for blog id 2 etc...
so essentially the id will be unique for each with "likescounter-" and corresponding blogid combied with it.
then in the button click function, simply do this
function likedpost(el){
var id = el.dataset.postid;
// Here's the reference to the element
// with jquery syntax it would be
var likesCounter = $("#likescounter-"+id)
// for vanilla js it would be
var likesCounter = document.getElementById("likescounter-"+id)
...
}

How can I get ID from "ul" dynamic tag

I have the next situation.
I have a button in HTML code. When I press one of the options from the button I call a function that constructs the content from other button.
I have a ul tag in HTML code with a list of li tags inside. The value of this li tags are generated dynamically with a query database.
When I generate the options from li tags I assign a different ID to each other.
Here you can see the code that I have for the second button:
<div class="dropdown" class="btn-group-lg" id="test">
<button name="selSensor" id="seltipoSensor" class="btn btn-primary dropdown-
toggle" type="submit" data-toggle="dropdown">
<span>Select one option</span>
</button>
<ul class="dropdown-menu" id="test2">
</ul>
</div>
Here you can see the code that I have to generate the li tags inside the button.
<script type="text/javascript">
function selectedUbi(ubicacion){
var datos = {
"arg" : ubicacion
};
$.ajax({
data: datos,
url: 'condatabase/calculos_bdd2.php',
type: 'post',
success: function (response) {
if(response){
document.getElementById("test2").innerHTML = "";
var ul = document.getElementById("test2");
for (i=0;i<response.length;i++){
var li = document.createElement("li");
li.appendChild(document.createTextNode(response[i][i+1]));
li.setAttribute("id", "element"+i);
li.setAttribute("onclick",myFunction);
ul.appendChild(li);
}
}
},
dataType:"json"
});
}
</script>
The question that I have is...
how can I get the ID from the li tag that I generate dynamically?
I tried to use "getElementByID" and "getElementByTagName" but as the ID is dynamic I have no idea to caught the value.
For example the button have the next options to select:
- apple (ID= element0)
- bannana (ID= element1)
- carrot (ID= element2)
When I select the option "bannana" I need to get the ID "element1".
You can use querySelectorAll on your container to get a list of elements and then read their attribute id.
function getIds(container){
return [...container.querySelectorAll('li[id]')].map(li => li.getAttribute('id'));
}
However, I would rather recommend to create a data layer abstraction to handle operations related to data fetching, etc... in order to avoid a strong coupling on your html structure and your "logic" code.
function createStore(){
return {
async fetch(arg){ /*... return your data (and cache it etc */ }
};
}
so your button handlers can share that "store"
const store = createStore();
document.getElementBy('button1').addEventListener('click', () => {
store.fetch().then(data => { /* do something with your data like updating html ... */})
});
document.getElementBy('button2').addEventListener('click', () => {
store.fetch().then(data => { /* do something with your data like updating html ... */})
});
//etc

Invoking a ViewComponent within another ViewComponent

I am currently coding within a ViewComponent (ViewComponent1) view. Within this View, I have listed a few items:
As you can see, the channels 11, 12, 13 and 14 are clickable. Each channel has some additional information (OBIS, avtalsid.. etc). What I´m trying to do is to invoke ViewComponent2, within ViewComponent1, and pass along some of the data, based on the clicked item.
What I tried to do is to create another View called "Test" and within that View invoke ViewComponent2 along with its parameters, like this:
<div class="row">
<div class="col-md-2 canalstyle">
<a asp-controller="Customer" asp-action="Test" asp-route-pod="#item.STATION"
asp-route-idnr="#item.IDNR" asp-route-kanal="#item.KANAL" asp-route-start="#Model.start"
asp-route-end="#Model.end"> #Html.DisplayFor(modelItem => item.KANAL)</a>
</div>
</div>
This works, but this method redirects me away from my current View (ViewComponent 1). I don't want that. I want the current view to load the additional information from ViewComponent2.
My function that runs the ajax:
function myFunction() {
var data = JSON.stringify({
'idnr': id,
'start': this.start,
'end': this.end
});
$.ajax({
url: '#Url.Action("Test2","Customer")',
type: 'GET',
data: { idnr: id, start: this.start, end: this.end },
contentType: 'application/json',
success: handleData(data)
})
};
function handleData(data) {
alert(data);
var url = $(this).attr("href");
var $target = $(this).closest("div").find(".details");
$.get(url, function (res) {
$target.html(res);
});
//do some stuff
}
And my Test2 Action:
public async Task<IActionResult> Test2(string idnr, string start, string end)
{
ServiceClient r2s = new R2S.ServiceClient();
R2S.Konstant[] kData = r2s.GetKonstantListAsync(new string[] { "IDNR" }, new string[] { idnr}).Result; // mätarnummer in... --> alla konstanter kopplade till denna.
return ViewComponent("MeterReader2", new { k = kData[0], start = start, end = end });
}
I am trying to target the same DOM.. Any ideas?
Your current code is rendering links (a tags) and normally clicking on a link will do a new GET request, which is what you are seeing , the redirect to the new action method.
If you do not want the redirect, but want to show the result of the second view component in same view, you should use ajax.
For example, If you want to show the result of second view component just below each link, you may add another html element for that. Here i am adding an empty div.
<div class="row">
<div class="col-md-2 canalstyle">
<a class="myClass" asp-controller="Customer" asp-action="DetailsVc"
asp-route-id="#item.Id" > #item.KANAL</a>
<div class="details"></div>
</div>
</div>
Here i just removed all those route params you had in your orignal question and replaced only with on param (id) . Assuming your items will have an Id property which is the unique id for the record(primary key) and using which you can get the entity (from a database or so) in your view component to get the details.
This will generate the link with css class myClass. You can see that, i used asp-action attribute value as "DetailsVc". We cannot directly use the view component name in the link tag helper as attribute value to generate the href value. So we should create a wrapper action method which returns your view component result such as below
public IActionResult DetailsVc(int id)
{
return ViewComponent("DetailsComponent", new { id =id });
}
Assuming your second view components name is DetailsComponent and it accepts an id param. Update the parameter list of this action method and view component as needed. (but i suggest passing just the unique Id value and get details in the server code again)
Now all you have to do is have some javascript code which listen to the click event on those a tags and prevent the normal behavior (redirect) and make an ajax call instead, use the ajax call result to update the details div next to the clicked link.
You can put this code in your main view (or in an external js file without the #section part)
#section Scripts
{
<script>
$(function() {
$("a.myClass").click(function(e) {
e.preventDefault();
var url = $(this).attr("href");
var $target = $(this).closest("div").find(".details");
$.get(url,function(res) {
$target.html(res);
});
});
});
</script>
}

Update dynamically generated list item (generated using PHP) after ajax call

The following HTML code is being echoed using a while loop in PHP which is adding a list item after fetching data from database.
PHP:
echo '
<li>
<div class="collapsible-header">
<div class = "left">
<div class = "issueStatusIcon" style = "background-color:'.$smallCircleColor.';">'.$smallMsg.'</div>
<span class = "issueTitle" style = "font-family: robotoBold">'.$issueTitle.'</span>
</div>
<div class = "issueButtonsGroup">
<form id = "archiveIssueForm'.$i.'" issue-name = "'.$issueTitle.'" action = "archiveIssue.php">
<input type = "hidden" value = "'.$issueID.'" name = "issueID"/>
</form>
<a class = "right archiveIconButton" onclick = "ajaxIssueArchive('.$i.')" href = "#">
<i class="material-icons black-text issueOptions archiveIcon">archive</i>
</a>
<a class = "right"><i class="material-icons black-text issueOptions">edit</i></a>
</div>
</div>
</li>
';
This is the preview image of the generated list:
Notice the cursor over the archive button which archives the list item. The class for that button is archiveIconButton (you can find it in the above code). When the button is clicked, archiveIssueForm is submitted via AJAX (each form has a unique identifier variable $i appended to its id).
Following is the JQuery AJAX code:
JQuery:
<script>
function ajaxIssueArchive($num){
$.ajax({
type: "post",
url: "archiveIssue.php",
data: $('#archiveIssueForm' + $num).serialize(),
success: function(data){
$fetchIssueName = $('#archiveIssueForm' + $num).attr("issue-name");
$toastText = $fetchIssueName + " has been archived";
Materialize.toast($toastText, 3000);
$('#archiveIssueForm' + $num).html(data);
}
});
}
</script>
After archiving any list item, it gets deleted from the database. I want to update the ul element which contains these list items so that the list item which gets deleted doesn't gets displayed after the AJAX form submission.
Assume the id of ul to be issueListUL.
What i'm currently getting is the whole code of the html page displayed in the li item. I am certainly doing something wrong, any help would be appreciated!
After archiving a list item:
I was able to solve this issue in the following way, The JQuery script in the question should be changed like this:
JQuery:
<script>
function ajaxIssueArchive($num){
$.ajax({
type: "post",
url: "archiveIssue.php",
data: $('#archiveIssueForm' + $num).serialize(),
success: function(data){
//assigning the updated ul's html to a variable
$afterIssueArchival = $(data).find("#issueListContainer").html();
//toast
$fetchIssueName = $('#archiveIssueForm' + $num).attr("issue-name");
$toastText = $fetchIssueName + " has been archived";
Materialize.toast($toastText, 3000);
//updation of ul's html, ID of the ul which contains all the list items is assumed to be 'listContainer'
$("#issueListContainer").html($afterIssueArchival);
}
});
}
</script>
When updating an element's html, just extract the element's updated html code from data attribute in the ajax code (as show in the above code) and update the existing element's html with it!
Hope this helps people with the same problem as mine! :D

Only slideUp the deleted message

I'm using a PM system and added the delete-message feature. I've got a form which checks for the message_id and message_title. The form posts to delete_message.php page which contains the query to delete the message. This has been done via Javascript as I dont want the page to refresh.
I've got two functions for this:
function deleteMessage() {
$.ajax({
url: "message/delete_message.php",
type: "POST",
data: $("#delMsgForm").serialize(),
success: function(data,textStatus,jqXHR){ finishDeleteMessage(data,textStatus,jqXHR); }
});
}
function finishDeleteMessage( data , textStatus ,jqXHR ) {
$(".inboxMessage").slideUp('slow');
}
Currently when I click on the delete button (image of a trashcan) it deletes the message without reloading the page, as a finishing touch, it slidesUp the divclass (inboxMessage) the message is in. Since I tell it to slide up this class, it slides up every message. This is my piece of code containing the classes and the form:
<div class="inboxMessage">
<div class="inboxMessageImg NoNewMsg"></div>
<div class="inboxMessageHeader">
<a id="ajax" class="inboxMessageLink" onclick="showMessage('.$row['message_id'].')">'.$row['message_title'].'</a>
<p class="inboxMessageStatus Read">'.$inboxMessageStatus_Read.'</p>
</div>
<div class="inboxMessageDescription">'.$inboxMessageDescription.'</div>
<div class="inboxMessageActions">
<form id="delMsgForm" name="delMsgForm" action="message/delete_message.php" method="post">
<input type="hidden" id="msgTitle" value="'.$row['message_title'].'" name="message_title">
<input type="hidden" id="msgID" value="'.$row['message_id'].'" name="message_id">
</form>
<input type="submit" id="ajax" value="" name="deleteMessageButton" class="deleteMessageIcon" onclick="deleteMessage()">
</div>
</div>
What I want it to do is to slideUp only the message which has just been deleted by the user. I know this has to be done by telling javascript to only slideUp the deleted message which contains the message_id and/or message_title.
I've tried several things, but no love whatsoever. I'm also not that familiar with javascript/ajax. Any help would be highly appreciate.
Cheers :)
where do you call deleteMessage from? indirect the function call through another function which knows the parent of your "trash can", and can call slide up on that specific one.
function deleteMessage (element) {
//element will be clicked button
var container = $(element).closest("div.inboxMessage"),
//container div including the trashcan
$.ajax({
url: "message/delete_message.php",
type: "POST",
data: $("#delMsgForm").serialize(),
success: function(data,textStatus,jqXHR){
finishDeleteMessage(container);
}
});
});
and this will be your button
<input type="submit" id="ajax" value="" name="deleteMessageButton" class="deleteMessageIcon" onclick="deleteMessage(this)">
Apparently, you've got more divs with class inboxMessage. Since you're adding this code:
$(".inboxMessage").slideUp('slow');
.. all divs with that class will remove. If you want just one div to remove, give it a unique ID or data-attribute and hide it that way.
For example: add the message-id to the div..
<div class="inboxMessage" id="(message_id)">
..and use..
$(".inboxMessage#message_id").slideUp('slow');
.. to slide up the right div.
Edit:
Add your message ID to the div and to the function deleteMessage(), so it will be deleteMessage(message_id).
function deleteMessage(message_id) {
$.ajax({
url: "message/delete_message.php",
type: "POST",
data: $("#delMsgForm").serialize(),
success: function(){ finishDeleteMessage(message_id); }
});
}
function finishDeleteMessage(message_id) {
$(".inboxMessage#"+message_id).slideUp('slow');
}

Categories