I have a bootstrap dropdown with multiple lis. and I need to call an action within the controller onClick the li.
but I always get this error
Uncaught (in promise) SyntaxError: Unexpected end of JSON input
lis looks like this
<ul class="dropdown-menu" aria-labelledby="btnGroup">
#foreach (var item in Model.tags)
{
<li class="d-flex justify-content-between">
<span style="cursor:pointer" class="dropdown-item w-75 itemTag">
#item.tagName
</span>
<i data-deleteUrl="#Url.Action("DeleteTag","EditorSections")?tag=#item.Id" class="bi bi-x-circle-fill w-25 deleteTag"></i>
</li>
}
</ul>
I use in the element i the dataset data-deleteUrl to pass the target url to the controller as follows
document.addEventListener('click', function (e) {
if (e.target && e.target.classList.contains('deleteTag')) {
var getUrl = e.target.dataset["deleteUrl"];
DeleteTag(getUrl, e.target);
}
});
function DeleteTag(url, e) {
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data);
if (data == "OK") {
var li = e.parentNode;
li.parentNode.removeChild(li);
}
});
return false;
};
but as I mentioned, It doesn't access the controller because I always get this error
Uncaught (in promise) SyntaxError: Unexpected end of JSON input
for more details, I provided some images
Note: when I was using inline onClick event it was working but when I started to use eventlistener instead I get the upmentioned error
<i onclick="DeleteTag('#Url.Action("DeleteTag","EditorSections")?tag=', this.parentElement)" class="bi bi-x-circle-fill float-end mx-3 deleteTag"></i>
Looks like part of the problem is using dataset["deleteUrl"] to extract from the element.
That implies an attribute data-delete-url. Browser will normalize data-deleteUrl to lower case.
You need to use dataset["deleteurl"] instead. I suggest you keep all your attributes in lowercase also
Demonstration:
const div = document.querySelector('div')
console.log(div.dataset)
<div data-deleteUrl="foo" data-delete-url="bar">Some content</div>
Related
I've written this bit of jQuery code in Oxygen Builder's JavaScript element to query the job board API and return an array of departments and their jobs. I'm testing to see if the department[0].jobs.length returns 0 then hide the #job-list div, otherwise show it and its associated jobs. The code succeeds in querying the API and returning 0 jobs but the remainder of the ternary operator will not hide the div.
jQuery(document).ready(function($) {
$.getJSON('https://boards-api.greenhouse.io/v1/boards/forwardnetworks/departments', postings => {
$("#div_block-420-61456").html(`
<div id="job-list">${postings.departments[0].jobs.length == 0 ? $("#job-list").hide() : $("#job-list").show()}<h3 class="dept">${postings.departments[0].name}</h3>
${postings.departments[0].jobs.map(item => `<h4 class="job-title">${item.title}</h4>
<p class="job-descrip">${item.location.name}`).join('')}</div> `);
});
});
I generally get a return of [object object]
As I mentioned in the comments, I would add a guard within the .getJSON success handler that will return early if there are no jobs to display.
The resulting function would be:
const departmentIndex = 0;
$(function ($) {
$.getJSON('https://boards-api.greenhouse.io/v1/boards/forwardnetworks/departments', postings => {
if (postings.departments[departmentIndex].jobs.length === 0) { return; }
$("#div_block-420-61456").html(`
<div id="job-list">
<h3 class="dept">${postings.departments[departmentIndex].name}</h3>
${postings.departments[departmentIndex].jobs.map(item => `
<a href="${item.absolute_url}">
<h4 class="job-title">${item.title}</h4>
</a>
<p class="job-descrip">${item.location.name}`
).join('')}
</div>
`);
});
});
Note: I put the index in a variable so that I could easily test with different departments.
Here is an example fiddle.
I have this ajax code that gets a res.json(event) from the server and then creates an object based on the value received.
Here is part of that code:
html += `<div class="card-header" id="headingOne-${i}">` +
`<div class="event-time"><time class="published" datetime="2017-03-24T18:18">${data[i].events.targetReminder} | ${data[i].events.targetAmPM}</time><div class="more"> <svg class="olymp-three-dots-icon"><use xlink:href="svg-icons/sprites/icons.svg#olymp-three-dots-icon"></use> </svg><ul class="more-dropdown"><li>Mark as Completed</li> <li>Delete Event </li></ul></div></div>` +
`<h5 class="mb-0 title"><a href="" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne" >${data[i].events.title}<i class="fa fa-angle-down" aria-hidden="true"></i>` +
` <span class="event-status-icon" data-toggle="modal" data-target="#public-event"><svg class="olymp-calendar-icon" data-toggle="tooltip" data-placement="top" id ="uncomplet-${i}"data-original-title="UNCOMPLETED"><use xlink:href="svg-icons/sprites/icons.svg#olymp-calendar-icon"></use></svg></span></a></h5></div>` +
`<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#headingOne-${i}"><div class="card-body" id="${data[i].events._id}" onClick="reply_click()">${data[i].events.caption}</div><div class="place inline-items"><svg class="olymp-add-a-place-icon"><use xlink:href="svg-icons/sprites/icons.svg#olymp-add-a-place-icon"></use></svg><span>${data[i].events.location}</span></div></div></div>`;
And here is the output of the code:
The aria-hidden that I'm talking about is this one
<div class="modal fade" id="public-event" tabindex="-1" role="dialog" aria-labelledby="public-event" aria-hidden="true">
What I have tried and already know it's not a proper solution is here
Code test
I created a script that change aria-hidden => true or false but I don't know how to link it with my box
<script type="text/javascript">
function reply_click()
{
document.getElementById('public-event').setAttribute('aria-hidden', 'false');
}
</script>
another failed try:
<script type="text/javascript">
function reply_click()
{
alert('this function is called')
$(`#mark-${i}`).onclick = function() {
document.getElementById('public-event').setAttribute('aria-hidden', 'false');
};
}
</script>
I also added in the HTML this function onClick="reply_click()" but nothing is happening. I only get the alert('this function is called')
Could you suggest me an idea, please?
By looking at your question and discussion on the comment section I think that you are trying to add click event on your dynamically generated div section(html part) and open the pop up modal.
We can achieve that by using $('#id' OR '.class').modal('show') in jquery.
So why don't you add a class any where inside your div section of html and bind a click function using jquery. Suppose you have added a class name showModal on the very first div after card-header like, div="card-header showModal"
$('#eventCard').on('click', '.showModal', function(){
$('#public-event').modal('show');
});
We cannot directly use $('.showModal').click...... because document structure is change after appending the html section after #eventCard which was initially was not present. Hpe this works.
could this be your problem ? you create an item dynamically with javascript, but the item you want to select, click event, is not actually created at that time. Once the item you want to export is created, you can select it and want to make the changes you want.
udpated: I added a snippet of what I meant. in order for me to select the H1 tag that occurs after I click on the button, I have to write a function that will occur after it occurs.
const button = document.querySelector(".clickme");
const container = document.querySelector(".container");
button.addEventListener("click", () => {
container.innerHTML += `
<h1 class = "change-modal"> ı cant select this</h1>
<div class="modal fade" id="public-event" tabindex="-1" role="dialog" aria-labelledby="public-event"
aria-hidden="true"> `
})
const changeModal = document.querySelector(".change-modal")
console.log(changeModal)
<button class="clickme">Click me</button>
<div class="container" style="background-color: red;">
</div>
<h1 class="change-modal">ı select this</h1>
updated2 :
for (let i = 0; i < data.length; i++) {
html += // your html
$("eventCard").append(html);
//after this, you can select the item and type the function because the items are created here.
}
Updated 3!!! : I explained how to do things with javascript without using jquery. Hopefully you know what I mean.
async getData() { // fetch operations using javascript
const data = await fetch(url); // your api url
const jsonToData = await data.json(); // here you can Request api and obtain the data
return jsonToData;
}
getData().then((data) => {
console.log(data) // ıts probably an array.
for (let data = 0; data < jsonToData.length; data++) {
// data operations, what if you want to
html += // you printed document items,
}
})
.then(() => {
//!!! IMPORTANT!!! this is where you need to perform the operation of selecting the element function. you can also write a function that can work for the code here, but I've written it one by one for now.
const clickedElement = //type whatever element you want to click on. !!
clickedElement.addEventListener("click", function() {
const elementToChange = document.getElementById(".public-event");
elementToChange.setAttribute('aria-hidden', 'false');
})
})
.catch(err => console.log(err))
The view in my html is not getting filtered on selecting any li element.
But when I console the filter functions the output generated is correct.Also how to clear the filter so it is reusable again.I'm getting a blank page on clicking open or close select elements.Can anyone help me with this.
I have used two filters in a controller inside the functions like this-
indexController Functions-
this.UserTickets = ()=> {
//code to get the tickets
}
this.openTickets = () => {
index.filteredTickets = $filter('filter')(index.tickets, { status: "open" } );
console.log(index.filteredTickets);
};
//filter closed tickets
this.closeTickets = () => {
index.filteredTickets = $filter('filter')(index.tickets, { status: "close" } );
console.log(index.filteredTickets);
};
this.clearFilter = () => {
//clear the filter
};
HTML-
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a ng-click="indexCtrl.clearfilter()">None</a></li>
<li><a ng-click="indexCtrl.openTickets()">Open</a></li>
<li><a ng-click="indexCtrl.closeTickets()">Close</a></li>
</ul>
<div ng-repeat="ticket in indexCtrl.tickets | filter:tickets |filter:indexCtrl.filteredTickets">
<div class="ticket-no">
<h4>Ticket No:<span>{{ticket}}</span></h4>
</div>
<div class="ticket-title">
<a ng-href="/ticketView/{{ticket.ticketid}}"><h3>{{ticket.title}}</h3></a>
</div>
<div class="ticket-info">
<p class="pull-left">{{ticket.username}} On {{ticket.created | date:"MMM d, y h:mm a"}}</p>
<p class="pull-right">Status:<span>{{ticket.status}}</span></p>
</div>
<hr class="hr">
</div>
You are mixing both angular filter options. I would recommend the javascript filters, index.filteredTickets=$filter('filter')(index.tickets,{status:"open"}); rather than the html template syntax, ng-repeat="ticket in indexCtrl.tickets | filter:tickets...". The key difference between these methods is how often they are run. The html template syntax filters are run on every digest cycle, the javascript filters are only run when the method is called, in your case, on each button click. For small apps or when the lists are small, this difference won't be noticeable, but if your app grows in size, the constant filtering on each digest cycle can cause page lag.
The filters in the controller are my preferred way of handling this, so I will show you how to clean up your code for these to work. You are almost there, just a few small changes are needed.
In your html, you can remove the inline filters in the ng-repeat, these aren't needed, and change the array to be your filter list, index.filteredTickets.
.html
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a ng-click="indexCtrl.clearfilter()">None</a></li>
<li><a ng-click="indexCtrl.openTickets()">Open</a></li>
<li><a ng-click="indexCtrl.closeTickets()">Close</a></li>
</ul>
<div ng-repeat="ticket in indexCtrl.filteredTickets">
<div class="ticket-no">
<h4>Ticket No:<span>{{ticket}}</span></h4>
</div>
<div class="ticket-title">
<a ng-href="/ticketView/{{ticket.ticketid}}"><h3>{{ticket.title}}</h3></a>
</div>
<div class="ticket-info">
<p class="pull-left">{{ticket.username}} On {{ticket.created | date:"MMM d, y h:mm a"}}</p>
<p class="pull-right">Status:<span>{{ticket.status}}</span></p>
</div>
<hr class="hr">
</div>
For the javascript, you need to make sure the filteredTickets are accessible in the html. I'm not sure if index == this, if not, you may need to attach the filtered tickets to the scope. The one other change needed is to set the filteredTickets to your original list if the none button is pressed. You will also want to call clearFilter after you load the list, otherwise index.filteredList will be undefined/null.
.js
this.UserTickets = () => {
//code to get the tickets
....
//after getting list, call clear filter
this.clearFilter();
}
this.openTickets = () => {
index.filteredTickets = $filter('filter')(index.tickets, { status: "open" } );
console.log(index.filteredTickets);
};
//filter closed tickets
this.closeTickets = () => {
index.filteredTickets = $filter('filter')(index.tickets, { status: "close" } );
console.log(index.filteredTickets);
};
this.clearFilter = () => {
//clear the filter
index.filteredTickets = index.tickets;
};
I have api call on $on i got the Json response that is attached with the question. i was able to display fileName in the li , Now i have delete function when user click on remove icon i am calling function and trying to get rskAsesAprvAtchKy key so i can post the key to backend to delete this file.
It is coming undefined i am not sure what i am missing any help will be appreciated..
main.html
<div class="row">
<div class="col-md-6">
<ul>
<li ng - repeat="file in attachedDoc">{{file . fileName}}
<a href="" ng - click="deleteFile()">
<span class="glyph_remove"></span>
</a>
</li>
</ul>
</div>
</div>
factory.js
$scope.$on('addEditAttest', function (s, attestorObj) {
$scope.attestorObj = attestorObj;
attestorFactory.getAttachedDocument($scope.attestorObj.riskAssessmentRoleAsgnKey)
.then(function (response) {
$scope.attachedDoc = response.data;
});
});
$scope.deleteFile = function () {
var fileKey;
$scope.attachedDoc.rskAsesAprvAtchKy = fileKey;
console.log("deleted", fileKey);
}
JSON.JS
[{
"rskAsesAprvAtchKy": 1001,
"fileName": "Doc 1",
"rskAsesRoleAsgnKy": 1277
}]
You can pass the key as parameter for the ng-click method:
At the view
<li ng-repeat="file in attachedDoc">{{file.fileName}}
<a href="" ng-click="deleteFile(file.rskAsesAprvAtchKy, $index)"> //Key from the file
<span class="glyph_remove">
</span>
</a>
</li>
Change the delete method
$scope.deleteFile = function(fileKey, fileIndex){
/*Delete the file*/
$scope.attachedDoc.splice(fileIndex, 1); //remove the file at position fileIndex
}
EDIT:
Passing the $index from the ng-repeat and using Array.splice() will do the job. See above.
I've been attempting to make my virgin query with JavaScript from a Parse database. I'd like to take data from a Parse column (named primary) and display it on the front end on a drop down. I've tried a large number of combinations but as of now I'm unable to make much progress. My Angular controller:
angular.module('startupApp')
.controller('bizOfferCtrl', function ($scope, $http) {
var primary = new Parse.Query(bizCategories);
$scope.getPrimary = function() {
$scope.bizCategories.relation("primary").query().find({
success: function(list) {
$scope.bizCategories.primary = list;
}
});
};
And the html (with bootstrap and SCSS) that goes along with that:
<div class="btn-group col-xs-4 col-sm-4 col-md-4 col col-lg-4" dropdown is-open="status.isopen">
<button type="button" class="btn btn-primary" dropdown-toggle>
{{getPrimary()}} <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" >
<li ng-repeat="category in bizCategories.primary">
{{category.primary}}
</li>
</ul>
</div>
You're not providing an error callback for the query, which could be used to provide insight into why your query is failing. See here.
You're also calling query().find() but you defined and bound the query to primary and Parse.Query is not a function, but an object. Try
primary.find({
success: function(list) {
$scope.bizCategories.primary = list;
}, error: function(error) {
// handle error
}
});
Also, I don't know if chaining the function call in the way you did is valid either, but I don't use Angular JS so I can't speak to the validity of this. From my perspective, it looks like you're trying to access it as a property of all of that.