I am trying to grab dynamically created information with ng-model (info created with ng-repeat). I am doing so in order to send the information in the form of an object to my flat database, Firebase. Unfortunately, the ng-model is only grabbing "" (empty strings) as my values. Any suggestions?
/////////// Controller below
// Bookmark object
$scope.bookmark = {
url: "",
illnessName: "",
symptom: ""
};
// Save illness card to bookmarks
$scope.saveToBookmarks = ($bookmark) => {
console.log($bookmark);
if ($scope.bookmark.illnessName === ""){
alert("Hey, quit that NAME!");
return;
}
if ($scope.bookmark.symptom === ""){
alert("Hey, quit that SYMPTOM!");
return;
}
if ($scope.bookmark.url === ""){
alert("Hey, quit that URL!");
return;
}
BookmarksFactory.addUserBookmark({
url: $scope.bookmark.url,
illnessName: $scope.bookmark.illnessName,
symptom: $scope.bookmark.symptom
});
console.log("$scope.bookmark.url :", $scope.bookmark.url);
};
///////// Factory below
"use strict";
app.factory("BookmarksFactory", function(FBCreds, $q, $http) {
var addUserBookmark = (newBookmark) =>{
console.log("Factory is working!");
return $q( (resolve, reject) => {
$http.post(`${FBCreds.databaseURL}/bookmarks.json`,
JSON.stringify(newBookmark))
.then( (FBObj) => {
resolve(FBObj);
})
.catch( (error) => {
reject(error);
});
});
};
return {
addUserBookmark
};
});
<!-- This will be search results populate -->
<div class="search-results" >
<div class="row">
<div class="col-lg-4 text-center search-card box" ng-repeat="illness in illnesses | filter: searchText.search">
<!-- Insert search results here -->
<div class="inner ">
<div class="card">
<button type="button" class="close close-card" aria-label="Close" ng-click="removeCard($event)">
<span class="close-card-x" aria-hidden="true">×</span>
</button>
<img class="card-img-top" src="{{illness.url}}" alt="Card image cap" ng-model="bookmark.url">
<div class="card-block">
<h4 class="card-title" ng-model="bookmark.illnessName">{{illness.illnessName}}</h4>
<p class="card-text" ng-model="bookmark.symptom">{{illness.symptom}}</p>
<button class="btn btn-primary" ng-click="saveToBookmarks(bookmark)">Save</button>
<button class="btn btn-success" ng-click="goToEditPage()">Edit</button>
</div>
</div>
</div>
</div>
</div>
</div>
change to $scope.bookmark ={};
and use http to get data file you code , example of me is test.php
$http(){
method:'POST',
url:'test.php',
data : $.param($scope.bookmark),
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(success)
function success(){
////
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I'm working on a Django REST Framework task. Every time I perform a Create, Retrieve, Update, and Delete function the list item of div is flashing every time.
How can I stop this flashing/flickering?
From API URL I have to display the paginated data. If I click the next page then also flickering is occurred. How can I get rid of this flickering/flashing issue?
main.html
{% extends 'todo/index.html' %}
{% block content %}
<div class="center-column" id="center-column">
<h5 class="card-title" id="welcome" data-id={{ request.user.id }}>
Hello {{ request.user.username }}, Create your todo list
</h5>
<div id="addTodoForm">
<form action="" method="">
<div class="input-group-append">
<input type="text" class="title-input" required name="title" placeholder="e.g. Chemistry">
<button type="submit" class="form-control btn btn-primary mr-sm-2" id="addTodobtn">
Add Todo
</button>
</div>
</form>
</div>
</div>
<div class="row" id="row">
<div class="col-sm-5">
<div class="card">
<div class="card-body">
<h5 class="card-title">
Incomplete Todo Items
</h5>
<hr />
<div class="list-group" id="incompleteTodo">
</div>
<hr>
<nav aria-label="..." id="incompletePagination">
<ul class="pagination justify-content-center">
<li class="page-item">
<button class="page-link" tabindex="-1" id="prevPageI">«</button>
</li>
<li class="page-item"><button class="page-link" id="currPageI">1</button></li>
<li class="page-item"><button class="page-link" id="nextPageI">»</button></li>
</ul>
</nav>
</div>
</div>
</div>
<div class="col-sm-5">
<div class="card">
<div class="card-body">
<h5 class="card-title">
Completed Todo Items
</h5>
<hr>
<div class="list-group" id="completedTodo">
</div>
<hr>
<nav aria-label="..." id="completedPagination">
<ul class="pagination justify-content-center">
<li class="page-item">
<button class="page-link" tabindex="-1" id="prevPageC">«</button>
</li>
<li class="page-item"><button class="page-link" id="currPageC">1</button></li>
<li class="page-item"><button class="page-link" id="nextPageC">»</button></li>
</ul>
</nav>
</div>
</div>
</div>
</div>
{% endblock %}
main.js
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let todo = 0; todo < cookies.length; todo++) {
const cookie = cookies[todo].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function taskStatus(item) {
return `
${item.map(task =>
`
<div class="card list-group-item list-group-item-danger mt-1" id="task_${task.id}">
<span class="font-italic">${task.heading}</span>
<div class="float-right">
<badge type="submit" class="badge badge-light" id="complete-task_${task.id}">
✔
</badge>
<badge type="submit" class="badge badge-warning ml-1" id="delete-task_${task.id}">
❌
</badge>
</div>
<div class="float-right">
<badge type="submit"
class="badge badge-dark mr-1 edit-task"
id="edit-task_${task.id}"
data-target="#updateTaskModal_${task.id}"
data-toggle="modal">
edit
</badge>
<div class="modal fade" id="updateTaskModal_${task.id}" tabindex="-1" role="dialog"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Update Todo</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="list-group-item list-group-item-warning">
<input type="text" required id='updateTaskInp_${task.id}' size='45'
name="heading_${task.id}" value="${task.heading}">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="updateTaskModalSubmit_${task.id}"
data-dismiss="modal">
Submit
</button>
</div>
</div>
</div>
</div>
</div>
</div>`
).join('')}
`
};
function taskCompleted(item) {
return `
${item.map(task =>
`
<div class="list-group-item bg-danger mb-1">
<span class="text-light font-italic">${task.heading}</span>
<div class="float-right">
<badge type="submit" class="badge badge-warning ml-1" id="delete-task_${task.id}">
❌
</badge>
</div>
</div>
`
).join('')}
`
};
$(document).ready(function() {
const incompleteHome = '/api/todo-incomplete/?incomplete=1';
const completedHome = '/api/todo-completed/?completed=1';
todoIncompleteItems(incompleteHome);
todoCompletedItems(completedHome);
// Create Todo Item
$('#addTodobtn').click(function(e) {
e.preventDefault();
var title = $(".title-input").val();
var user_id = $('#welcome').data('id');
console.log("Title: ", title)
$.ajax({
url: "api/create-todo/",
type: "POST",
headers:{
"X-CSRFToken":csrftoken
},
data: {
"title": title,
"user_id": user_id,
},
success: function(data) {
$("#incompleteTodo").html('');
todoIncompleteItems(incompleteHome);
},
error: function(err) {
alert("check the console for errors");
console.log("Create Todo Item Error: ", err)
}
})
$(".title-input").val('');
})
var nextIncomplete = null;
var prevIncomplete = null;
var currentPageIncomplete = null;
var currentIncomplete = null;
$('#nextPageI').click(function() {
currentIncomplete +=1
$('#currPageI').html(currentIncomplete)
todoIncompleteItems(nextIncomplete);
})
$('#prevPageI').click(function() {
currentIncomplete -= 1
$('#currPageI').html(currentIncomplete)
todoIncompleteItems(prevIncomplete);
})
// Page wise Incomplete Todo Items
function todoIncompleteItems(incompleteUrl) {
$('#incompleteTodo').html('');
$.ajax({
url: incompleteUrl,
type: 'GET',
success: function(data) {
currentPageIncomplete = `api/todo-incomplete/?incomplete=${data.current_page_no}`;
currentIncomplete = data.current_page_no;
nextIncomplete = data.next;
if (data.next != null) {
$('#nextPageI').css("visibility", "visible")
} else {
$('#nextPageI').css("visibility", "hidden")
}
prevIncomplete = data.previous;
if (data.previous != null) {
$('#prevPageI').css("visibility", "visible")
} else {
$('#prevPageI').css("visibility", "hidden")
}
if (data.next === null && data.previous === null) {
$('#incompletePagination').css("visibility", "hidden")
} else {
$('#incompletePagination').css("visibility", "vidible")
}
let todoItems = data.results;
for (let todo in todoItems) {
$('#incompleteTodo').append(
`<div class="list-group-item list-group-item-primary mb-1" id="todo-${todo}"
data-id="${todoItems[todo].id}">
<span class="font-weight-bold">${todoItems[todo].title}</span>
<div class="float-right">
<badge type="submit" class="badge badge-warning" id="deleteTodo_${todoItems[todo].id}">
❌
</badge>
</div>
<div class="float-right">
<badge type="submit" class="badge badge-light mr-1"
id="completed-todo_${todoItems[todo].id}">
✔
</badge>
</div>
<div class="float-right">
<badge type="submit" class="badge badge-dark mr-1 edit"
data-target="#updateTodoModal_${todoItems[todo].id}" data-toggle="modal">
edit
</badge>
<div class="modal" id="updateTodoModal_${todoItems[todo].id}" tabindex="-1"
role="dialog" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Update Todo</h5>
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="list-group-item list-group-item-warning">
<input type="text" id='updateTodoInp_${todoItems[todo].id}'
size="45" value="${todoItems[todo].title}">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button type="button" class="btn btn-primary"
id="updateModalSubmit_${todoItems[todo].id}" data-dismiss="modal">
Submit
</button>
</div>
</div>
</div>
</div>
</div>
<div class="float-right mr-1">
<badge type="submit" class="badge badge-primary add-task" data-toggle="modal"
data-target="#addTaskModal_${todoItems[todo].id}">
✚
</badge>
<div class="modal" id="addTaskModal_${todoItems[todo].id}" tabindex="-1" role="dialog"
aria-labelledby="taskModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="taskModalLabel">
Add New Task for ${todoItems[todo].title}
</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="list-group-item list-group-item-dark">
<input type="text" required id='addTaskInp_${todoItems[todo].id}' size="45"
name="heading" placeholder="Enter the task name here...">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary closeModal"
data-dismiss="modal">
Close
</button>
<button type="button" class="btn btn-primary"
id="taskSubmit_${todoItems[todo].id}" data-dismiss="modal">
Submit
</button>
</div>
</div>
</div>
</div>
</div>
<div class="mt-3 incompleteTodo-task">
${todoItems[todo].tasks ? taskStatus(todoItems[todo].tasks) : ''}
</div>
</div>
`
)
};
for (var todo in todoItems) {
var deleteTodoBtn = document.querySelector(`#deleteTodo_${todoItems[todo].id}`)
var taskSubmitBtn = document.querySelector(`#taskSubmit_${todoItems[todo].id}`)
var editTodoBtn = document.querySelector(`#updateModalSubmit_${todoItems[todo].id}`)
var completedTodoBtn = document.querySelector(`#completed-todo_${todoItems[todo].id}`)
deleteTodoBtn.addEventListener('click', (function(element) {
return function() {
deleteTodo(element)
}
})(todoItems[todo]))
taskSubmitBtn.addEventListener('click', (function(element) {
return function() {
addTaskItem(element)
}
})(todoItems[todo]))
editTodoBtn.addEventListener('click', (function(element) {
return function() {
editTodoItem(element)
}
})(todoItems[todo]))
completedTodoBtn.addEventListener('click', (function(element) {
return function() {
completedTodo(element)
}
})(todoItems[todo]))
var taskItems = todoItems[todo].tasks
for (var task in taskItems) {
var deleteTaskBtn = document.querySelector(`#delete-task_${taskItems[task].id}`)
var completeTaskBtn = document.querySelector(`#complete-task_${taskItems[task].id}`)
var editTaskBtn = document.querySelector(`#updateTaskModalSubmit_${taskItems[task].id}`)
deleteTaskBtn.addEventListener('click', (function(element) {
return function() {
deleteTask(element)
}
})(taskItems[task]))
completeTaskBtn.addEventListener('click', (function(element) {
return function() {
completedTask(element)
}
})(taskItems[task]))
editTaskBtn.addEventListener('click', (function(element) {
return function() {
editTaskItem(element)
}
})(taskItems[task]))
if(taskItems[task].completed === true) {
$(`#task_${taskItems[task].id}`).removeClass("list-group-item-danger")
$(`#task_${taskItems[task].id}`).addClass("list-group-item-dark")
$(`#edit-task_${taskItems[task].id}`).remove()
$(`#complete-task_${taskItems[task].id}`).remove()
}
}
}
},
error: function(err) {
console.log(err)
}
});
}
var nextCompleted = null;
var prevCompleted = null;
var currentPageCompleted = null;
var currentCompleted = null;
$('#nextPageC').click(function() {
currentCompleted +=1
$('#currPageC').html(currentCompleted)
todoCompletedItems(nextCompleted);
})
$('#prevPageC').click(function() {
currentCompleted -=1
$('#currPageC').html(currentCompleted)
todoCompletedItems(prevCompleted);
})
// Page wise Completed Todo Items
function todoCompletedItems(CompletedUrl) {
$('#completedTodo').html('');
$.ajax({
url: CompletedUrl,
type: 'GET',
success: function(data) {
var todoItems = data.results;
currentPageCompleted = `api/todo-completed/?completed=${data.current_page_no}`
currentCompleted = data.current_page_no
nextCompleted = data.next;
if (data.next != null) {
$('#nextPageC').css("visibility", "visible")
} else {
$('#nextPageC').css("visibility", "hidden")
}
prevCompleted = data.previous;
if (data.previous != null) {
$('#prevPageC').css("visibility", "visible")
} else {
$('#prevPageC').css("visibility", "hidden")
}
if (data.next === null && data.previous === null) {
$('#completedPagination').css("visibility", "hidden")
} else {
$('#completedPagination').css("visibility", "visible")
}
for (var todo in todoItems) {
$('#completedTodo').append(
`
<div class="list-group-item bg-success mb-1"
id="todo_${todoItems[todo].id}" data-id="${todoItems[todo].id}">
<span class="text-light font-weight-bold">${todoItems[todo].title}</span>
<div class="float-right">
<badge type="submit" class="badge badge-warning mr-2"
id="deleteTodo_${todoItems[todo].id}">
❌
</badge>
</div>
<div class="completedTodoTask mt-3">
${todoItems[todo].tasks ? taskCompleted(todoItems[todo].tasks) : ''}
</div>
</div>
`
)
}
for (var todo in todoItems) {
var deleteTodoBtn = document.getElementById(`deleteTodo_${todoItems[todo].id}`)
deleteTodoBtn.addEventListener('click', (function(item) {
return function() {
deleteTodo(item)
}
})(todoItems[todo]))
var taskItems = todoItems[todo].tasks
for (var task in taskItems) {
var deleteTaskBtn = document.getElementById(`delete-task_${taskItems[task].id}`)
deleteTaskBtn.addEventListener('click', (function(element) {
return function() {
deleteTask(element)
}
})(taskItems[task]))
}
}
},
error: function(err) {
console.log(err);
}
})
}
function editTodoItem(item) {
var user_id = $('#welcome').data('id');
var title = $(`#updateTodoInp_${item.id}`).val();
$.ajax({
url: `api/update-todo/${item.id}/`,
type: 'POST',
headers:{
"X-CSRFToken":csrftoken
},
data: {
'title': title,
'user_id': user_id,
},
success: function(data) {
todoIncompleteItems(currentPageIncomplete);
},
error: function(data) {
alert("check the console for errors")
console.log('Problem in updating todo item: ', data)
}
})
}
function addTaskItem(item) {
var heading = $(`#addTaskInp_${item.id}`).val();
var user_id = $('#welcome').data('id')
$.ajax({
url: 'api/create-task/',
type: 'POST',
data: {
'heading': heading,
'user': user_id,
'todo': item.id,
'csrfmiddlewaretoken': csrftoken,
},
success: function(data) {
todoIncompleteItems(currentPageIncomplete);
},
error: function(data) {
alert("check the console for errors")
console.log('Problem in adding new task item: ', data)
}
})
}
function completedTodo(item) {
var user_id = $('#welcome').data('id')
$.ajax({
url: `api/completeTodoTask/${item.id}/`,
type: 'POST',
headers:{
"X-CSRFToken":csrftoken
},
data: {
'title': item.title,
'user_id': user_id,
'completed': true,
},
success: function(data) {
todoIncompleteItems(currentPageIncomplete);
todoCompletedItems(completedHome);
},
error: function(data) {
alert("check the console for errors")
console.log('Problem in Completing Todo item: ', data)
}
})
}
function deleteTodo(item) {
$.ajax({
url: `api/delete-todo/${item.id}/`,
type: 'DELETE',
headers: {
"X-CSRFToken": csrftoken,
},
success: function(data) {
todoIncompleteItems(currentPageIncomplete);
todoCompletedItems(currentPageCompleted);
},
error: function(data) {
alert("check the console for errors")
console.log("There was an error while deleting Todo Item: ", data)
}
})
}
function editTaskItem(item) {
var user_id = $('#welcome').data('id');
var heading = $(`#updateTaskInp_${item.id}`).val();
$.ajax({
url: `api/update-task/${item.id}/`,
type: 'POST',
headers:{
"X-CSRFToken":csrftoken
},
data: {
'heading': heading,
'user': user_id,
'todo': item.todo,
},
success: function(data) {
todoIncompleteItems(currentPageIncomplete);
},
error: function(err) {
alert("check the console for errors")
console.log("There was an error while deleting Task Item: ", data)
}
})
}
function completedTask(item) {
var user_id = $('#welcome').data('id')
$.ajax({
url: `api/complete-task/${item.id}/`,
type: 'POST',
data: {
'heading': item.heading,
'user': user_id,
'completed': true,
'title': 'title',
'user_id': user_id,
'csrfmiddlewaretoken': csrftoken,
},
success: function(data) {
todoIncompleteItems(currentPageIncomplete);
todoCompletedItems(completedHome);
},
error: function(data) {
console.log('Problem in Completing Task item: ', data)
}
})
}
function deleteTask(item) {
console.log("Delete Task Button Clicked: ", item.heading)
$.ajax({
url: `api/delete-task/${item.id}/`,
type: 'DELETE',
headers: {
"X-CSRFToken": csrftoken,
},
success: function(data) {
todoIncompleteItems(currentPageIncomplete);
todoCompletedItems(currentPageCompleted);
},
error: function(data) {
alert("check the console for errors")
console.log("There was an error while deleting Task Item: ", data)
}
})
}
})
At first, I have removed $("#incompleteTodo").html("") from the main.js file.
Then, Created let todo_incomplete = []; outside the function for storing the data
locally and add ed
let todoItems = data.results;
for (let todo in todoItems) {
try {
document.getElementById(`todo_${todo}`).remove();
} catch(err){}
}
After the loop ends, I have added
if(todo_incomplete.length > todoItems.length){
for (var i = todoItems.length; i < todo_incomplete.length; i++){
document.getElementById(`todo_${i}`).remove();
}
}
todo_incomplete = todoItems;
I used this method and it's working fine. I haven't found any solutions for this.
On implementing the same method for completed_Items I was able to achieve on bot the list's.
You can check this YouTube video, timestamp 49:00
Sorry for the long post, but I tried explaining things in as much detail as possible.
So as I dive deeper into JavaScript and start learning more and more about AJAX requests and other components, I've stumbled across something that I can't seem to figure out.
So below, I will explain what I'm doing and what I would like to do, and see if someone has some guidance for me.
So here is my Vue.js app:
new Vue({
name: 'o365-edit-modal',
el: '#o365-modal-edit',
data: function() {
return {
list: {},
}
},
created() {
this.fetchApplicationsMenu();
},
methods: {
fetchApplicationsMenu() {
var self = this;
wp.apiRequest( {
path: 'fh/v1/menus/applications',
method: 'GET',
}).then(menu => self.list = menu.data);
},
changed() {
const selected = this.$data.list.selected;
function get_ids(list, field) {
const output = [];
for (let i=0; i < list.length ; ++i)
output.push(list[i][field]);
return output;
}
const result = get_ids(selected, "id");
wp.apiRequest( {
path: 'fh/v1/menus/applications',
method: 'PUT',
data: {
ids: result,
},
}).then((post) => {
return post;
},
(error) => {
console.log(error);
});
},
add(x) {
this.$data.list.selected.push(...this.$data.list.available.splice(x, 1));
this.changed();
},
remove(x) {
this.$data.list.available.push(...this.$data.list.selected.splice(x, 1));
this.changed();
},
},
});
Then here is the HTML portion that I'm using to render the two columns:
<div class="column is-half-desktop is-full-mobile buttons">
<nav class="level is-mobile mb-0">
<div class="level-left">
<div class="level-item is-size-5 has-text-left">Selected</div>
</div>
<div class="level-right">
<div class="level-item">
<i class="fas fa-sort-alpha-up is-clickable"></i>
</div>
</div>
</nav>
<hr class="mt-1 mb-3">
<draggable class="list-group"
v-model="list.selected"
v-bind="dragOptions"
:list="list.selected"
:move="onMove"
#change="changed">
<button class="button is-fullwidth is-flex list-group-item o365_app_handle level is-mobile" v-for="(app, index) in list.selected" :key="app.id">
<div class="level-left">
<span class="icon" aria-hidden="true">
<img :src="app.icon_url" />
</span>
<span>{{app.name}}</span>
</div>
<div class="level-right">
<span class="icon has-text-danger is-clickable" #click="remove(index)">
<i class="fas fa-times"></i>
</span>
</div>
</button>
</draggable>
</div>
<div class="column is-half-desktop is-full-mobile buttons">
<div class="is-size-5 has-text-left">Available</div>
<hr class="mt-1 mb-3">
<draggable class="list-group"
v-model="list.available"
v-bind="dragOptions"
:list="list.available"
:move="onMove">
<button class="button is-fullwidth is-flex list-group-item o365_app_handle level is-mobile" v-for="(app, index) in list.available" :key="app.id">
<div class="level-left">
<span class="icon" aria-hidden="true">
<img :src="app.icon_url" />
</span>
<span>{{app.name}}</span>
</div>
<div class="level-right">
<span class="icon has-text-primary is-clickable" #click="add(index)">
<i class="fas fa-plus"></i>
</span>
</div>
</button>
</draggable>
</div>
That outputs the following items, and all works great. See the video display below of each component working as needed. This all works great! I'm calling the changed() method on add and remove which grabs all the IDs and stores them in the DB via an endpoint.
The Problem:
Now I have the following dropdown menu, which depends on the fh/v1/menus/applications endpoint to pull in all the items as shown below:
As you can see below, when I open the dropdown, it has three apps, when I open the cog wheel and remove one of the apps and it saves it but the dropdown doesn't get automatically updated, I have to refresh the page and then I will see the updates.
Does anyone know how to fetch the new items without a refresh?
Here is the HTML and the JS for the dropdown piece:
HTML: As you can see in there, I have data-source="applications" which pulls in the items inside the init_menu as shown in the JS.
<div class="dropdown-menu" id="dropdown-o365" role="menu">
<div class="dropdown-content">
<div class="container is-fluid px-4 pb-4">
<?php if ($application = Applications::init()): ?>
<div class="columns">
<div class="dropdown-item column is-full has-text-centered is-size-6">
<div class="level is-mobile">
<div class="level-left">
<?= $application->get_name() ?>
</div>
<div class="level-right">
<a class="navbar-item modal-element icon" id="o365-apps-cogwheel" data-target="o365-modal-edit" aria-haspopup="true">
<i class="fa fa-cog"></i>
</a>
</div>
</div>
</div>
</div>
<div class="columns is-multiline" data-source="applications"></div>
<?php else: ?>
<div class="columns">
<div class="column is-full">
No applications present.
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
Then here is the JavaScript. I initilize the method inside DOMContentLoaded using init_menu('applications');:
function init_menu(paths)
{
paths.forEach(path => {
const target = document.querySelector('[data-source=' + path + ']');
if (target) {
wp.api.loadPromise.done(function () {
const Menus = wp.api.models.Post.extend({
url: wpApiSettings.root + 'fh/v1/menus/' + path,
});
const menus = new Menus();
menus.fetch().then(posts => {
// This returns the data object.
const data = posts.data;
let post_list;
// Check if it's an array and see if selected is empty otherwise show available.
if (Array.isArray(data.selected) && data.selected.length !== 0) {
post_list = data.selected;
} else {
post_list = data.available;
}
post_list.forEach(function (post) {
switch(path) {
case 'applications':
target.appendChild(create_apps_dom_tree(post));
break;
default:
console.log('Path route is invalid.');
break;
}
})
})
})
}
});
}
function create_apps_dom_tree(post) {
const {
icon_url,
url,
name,
} = post
const container = document.createElement('div');
container.className = 'column is-one-third is-flex py-0';
const anchor = document.createElement('a');
anchor.href = url;
anchor.className = 'dropdown-item px-2 is-flex is-align-items-center';
const figure = document.createElement('figure');
figure.className = 'image is-32x32 is-flex';
const img = document.createElement('img');
img.src = icon_url;
const span = document.createElement('span');
span.className = 'pl-2';
span.textContent = name;
figure.appendChild(img);
anchor.append(figure, span);
container.appendChild(anchor);
return container;
}
If anyone has some guidance or an answer on how to pull in live data from the database on the fly, that would be amazing.
Basically, I need my data-source: to automatically grab the items when my vue/db request is sent so I don't have to refresh the page.
Inside my Vue app, I have the following method:
fetchApplicationsMenu() {
var self = this;
wp.apiRequest( {
path: 'fh/v1/menus/applications',
method: 'GET',
}).then(menu => self.list = menu.data);
},
which calls a GET request and then stores the data inside the return { list: {} }.
A quick fix might be to just invoke init_menu() from the component's beforeDestroy() hook, called when the dialog closes. You might choose to do it from changed() instead if the dropdown is still accessible with this dialog open.
new Vue({
// option 1:
beforeDestroy() {
init_menu('applications');
},
// option 2:
methods: {
changed() {
init_menu('applications');
}
}
})
Alternative: You already know what the final application list is in changed(), so you could update the dropdown with the new list from that method.
function update_menu(path, post_list) {
const target = document.querySelector('[data-source=' + path + ']');
// remove all existing children
Array.from(target.childNodes).forEach(x => x.remove());
post_list.forEach(post => target.appendChild(create_apps_dom_tree(post)))
}
new Vue({
methods: {
changed() {
update_menu('applications', this.$data.available);
}
}
})
This question already has answers here:
Remove elements onclick (including the remove button itself) with jQuery
(3 answers)
Closed 2 years ago.
function renderlist(doc) {
const listmon = document.querySelector("#item-list");
db.collection("cafes")
.get()
.then((snapshot) => {
list(snapshot.docs);
});
const list = (data) => {
let html = "";
data.forEach((doc) => {
const guide = doc.data();
auth.onAuthStateChanged((user) => {
if (user) {
const li = `<li class=${user.uid}>
<div class="card">
<a
href="#"
class="btn btn-fix text-left"
data-toggle="modal"
data-target="#exampleModal"
>
<div class="card-block">
<h4 class="card-title text-dark">${guide.name}</h4>
<p class="card-text text-dark">
${guide.city}
</p>
<a href="#" class="btn btn-primary" id="delete" onclick="arun (){
console.log("clicked");
};">delete</a>
<p class="card-text">
<small class="text-muted">Last updated 3 mins ago</small>
</p>
</div>
</a>
</div>
</li>
<div
class="modal "
id="exampleModal"
tabindex="-1"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div
class="modal-body"
data-toggle="modal"
data-target="#exampleModal"
>
${guide.name}
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>`;
html += li;
listmon.innerHTML = html;
} else {
console.log("logged out");
}
});
});
};
}
i created it using javascript and i want to remove it by clicking a button also i have used user uid as the lists id, when ever i click the button it should remove the list and from cloud firestore it would also be great if somebody could tell me how to only show users data to that particular user,sorry for the language and thanks in advance
I created this simple example to list users with the methods add, delete and show info.
These Firestore/firebase documents [Queries | Modify a document | resource parts ] can be helpful for you to understand better the methods that I used, please feel free to modify this code.
<html>
<head>
<script src="https://www.gstatic.com/firebasejs/7.18.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.18.0/firebase-firestore.js"></script>
</head>
<body>
<h1>Users</h1>
<div class="content">
<form id="add-user-form">
<input type="text" name="name" placeholder="user Name">
<input type="text" name="location" placeholder="user Location">
<button type="submit">Submit</button>
</form>
<ul id="user-list">
<div id="loader">Loading...</div>
</ul>
</div>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const userList = document.querySelector("#user-list");
const form = document.querySelector("#add-user-form");
//add listener to form, to create new users and avoid default form action
form.addEventListener("submit", e => {
e.preventDefault();
db.collection("users").add({
name: form.name.value,
location: form.location.value
});
form.name.value = "";
form.location.value = "";
});
//Create the users list with the firestore data
function renderuser(doc) {
//creating html elements
let li = document.createElement("li");
let name = document.createElement("span");
let del = document.createElement("button");
let info = document.createElement("button")
//add docuemnt ID to the list element
li.setAttribute("data-id", doc.id);
name.textContent = doc.data().name ;
location.textContent = doc.data().location;
//labels of the buttons
// i= info and x= delete user
info.textContent="i"
del.textContent = "X";
// add onclick action to the buttons
del.onclick=function(){deleteUser(doc.id);}
info.onclick=function(){getData(doc.id);}
// add elements to the list element
li.appendChild(name);
li.appendChild(del);
li.appendChild(info);
// add list element to the list
userList.appendChild(li);
}
function deleteUser(id){
db.collection("users")
.doc(id)
.delete();
}
// Getting Data
function getData(id) {
// __name__ is the reference for the id in firestore
db.collection("users").where("__name__", "==", id).get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
console.log(doc)
//this alert simulate the modal
alert("name: "+doc.data().name+"\nlocation: "+doc.data().location)
});
})
}
//this is not used but this is the method to update the data of a docuemnt(User)
function updateData(id,name,location){
db.collection("users").doc(id).set({
name: name,
location: location
}).then(function() {
alert("Document successfully written!");
})
.catch(function(error) {
alert("Error writing document: ", error);
});
}
// Realtime listener
// this function keep updated the list
function getRealtimeData() {
document.querySelector("#loader").style.display = "block";
//query all users
db.collection("users")
.orderBy("name")
.onSnapshot(snapshot => {
document.querySelector("#loader").style.display = "none";
let changes = snapshot.docChanges();
changes.forEach(change => {
if (change.type === "added") {
//add new users to the list on frist load this create the list of existent users
renderuser(change.doc);
} else if (change.type === "removed") {
//if an user is deleted this will remove the element of the list
let li = userList.querySelector(`[data-id=${change.doc.id}]`);
userList.removeChild(li);
}
});
});
}
//first run
getRealtimeData();
</script>
</body>
</html>
I need some help with computed properties and ajax in vue.
"filterFactories" is a list of factories.
The computed property "filterFactories" creates this list of factories.
Now, I want a new feature:
I have a button for an ajax request which get some new factories.
I want set the computed property "filterFactories" after an ajax request.
Unfortunately nothing happens.
it makes no difference:
1. this.filterFactories = response;
or
2. window.filterFactories = response;
In both cases - nothing happened
Is it possible to update the "filterFactories" after the successfull ajax request?
I have added a larger code snipped
<div id="app">
<div id="filter">
<div class="row">
<div class="col-md-12">
<div class="input-group">
<span class="input-group-addon">Factory</span>
<input type="text" class="form-control" placeholder="Name" aria-describedby="basic-addon1" v-model="searchFactory">
<div class="input-group-btn">
<button class="btn btn-default" type="submit" v-on:click="clearSearchFactory">
<i class="fa fa-times"></i>
</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-6">
<Multiselect
v-model="selectedCapabilities"
:options="allCapabilities"
label="name"
placeholder= "Select capabilities"
track-by="id"
:multiple="true"
></Multiselect>
</div>
<div class="col-xs-12 col-md-6">
<Multiselect
v-model="selectedCountries"
:options="allCountries"
label="name"
placeholder= "Select countries"
track-by="code"
:multiple="true"
></Multiselect>
</div>
</div>
</div>
<!--Modal-->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">{{this.clickedCapability.name}}</h4>
</div>
<div class="modal-body">
<!--......-->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal" #click="filterProperties">OK</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="row" style="height: 35px; margin: 10px">
<button type="button" class="btn btn-outline-dark" v-for="cap in selectedCapabilities" #click="modalCapClicked(cap)" data-toggle="modal" data-target="#myModal"> {{ cap.name }} <i class="fa fa-cogs"></i></button>
</div>
<!--Factories-->
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-3 col-lg-2" id="myCard-wrapper" v-for="factory in this.filterFactories">
<!--a list of factories-->
</div>
</div>
</div>
<script>
window.app = new Vue({
el: '#app',
components: {
Multiselect: window.VueMultiselect.default
},
data() {
return {
//Capabilities
allCapabilities: [], // alle Capabilities aus der Konfiguration die über das Json übermittelt wurden
selectedCapabilities: [], // selektierte Capabilities
clickedCapability: '', // im Modalfenster geöffnete Capability
//Countries
selectedCountries: [], // selektierte Countries
allCountries: [], // alle Countries aus der Json
//Factories
searchFactory: '', // Freitext Suchfeld für Fabriken
factories: [] // angezeigte Fabriken
}
},
computed:{
/* Filtert die Fabriken anhand der Kriterien: Suche-Input, Capabilities, Countries */
filterFactories: function(){
var filteredFactories = [];
var allFilter = [];
allFilter.push(this.filterFactoriesBySearchInput());
allFilter.push(this.filterFactoriesByCaps());
allFilter.push(this.filterFactoriesByCountries());
filteredFactories = allFilter.shift().filter(function(v) {
return allFilter.every(function(a) {
return a.indexOf(v) !== -1;
});
});
return filteredFactories;
}
},
methods: {
/* Filtert anhand der Suchfeld-Eingabe */
filterFactoriesBySearchInput(){
/*filter an return a new list of factories*/
},
/* Filtert anhand der Capabilities */
filterFactoriesByCaps(){
/*filter an return a new list of factories*/
},
/* Filtert anhand der Countries */
filterFactoriesByCountries(){
/*filter an return a new list of factories*/
},
/* Setzt die aktuell im Modal-Fenster geöffnete Capability */
modalCapClicked(cap){
this.clickedCapability = cap;
}
filterProperties(){
axios.post('.....................................')
.then(function (response) {
this.factories = response.data.factoriesJson;
})
.catch(function (error) {
console.log(error);
});
},
clearSearchFactory(){
this.searchFactory = [];
}
},
beforeMount(){
axios.get('.........').then(response => {
this.factories = response.data.elementsJson.factories;
this.allCapabilities = response.data.elementsJson.config.capabilities;
});
axios.get('.......').then(response => {
this.allCountries = response.data;
});
}
})
</script>
Vue uses some magic for computed properties: it scans the function code and will automatically create watchers for the properties it finds within the code. This works well for simple situations but has failed many times for me with loops, map, reduce, etc.
I use multiple workarounds as needed, what is simplest to understand is this: create an artificial property which you reference in the computed prop and then update as needed:
new Vue({
data: {
updated: 0,
},
computed: {
myComputed(): {
// ...
// just a reference to the prop
this.updated;
},
},
methods: {
myAjax(): {
// ...
// modifying the prop will trigger update of myComputed
this.updated++;
},
},
});
Of course you should use names more appropriate to the use cases you have, however i have instances where i just called this property "updateDummy" ;)
I am retrieving friend objects via facebook graph API. The idea is to display a list of the names of returned friends, allow user to select one or more friends from this list, and determine the IDs of the friends selected by user once a button is clicked.
So far, I have the following code...
detail.js:
Template.detail.helpers({
...
listOfFriends: function() {
var list = new Array();
if (Meteor.user()) {
list = Meteor.user().profile.listOfFriends;
}
return list;
},
...
});
Template.detail.events({
...
'click .select-friends': function(e) {
e.preventDefault();
// Display modal.
$('#friend_list_modal').modal('show');
Meteor.call('getFacebookFriends', function(err, response) {
if (err) {
alert(JSON.stringify(err));
} else {
if (response.statusCode != 200) {
alert("Error: " + response.statusCode);
}
}
});
},
'click #get_ids_button': function(e) {
e.preventDefault();
var checkedFriendNames = {}, counter = 0;
$("#friend_list li.active").each(function(idx, li) {
checkedFriendNames[counter] = $(li).text();
counter++;
});
// At this point, I have a list of names in checkedFriendNames,
// but I want the IDs and maybe other attributes as well.
$('#friend_list_modal').modal('hide');
}
});
detail.html:
<template name="detail">
<div class="page page-detail">
...
<div class="container">
<div class="btn btn-danger list-friends pull-right" data-toggle="tooltip" title="list friends">
<span class="glyphicon glyphicon-user"></span>
</div>
</div>
</div>
<!-- Modal -->
<div id="friend_list_modal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">List of Friends</h4>
</div>
<div class="modal-body">
<div>
<div style="max-height: 300px; overflow: auto;">
<ul id="friend_list" class="list-group checked-list-box">
{{#each listOfFriends}}
<li class="list-group-item">{{name}}</li>
{{/each}}
</ul>
</div>
</div>
</div>
<div class="modal-footer">
<button id="get_ids_button" type="button" class="btn btn-default">Get IDs</button>
</div>
</div>
</div>
</div>
</template>
server.js:
Meteor.methods({
...
getFacebookFriends: function() {
this.unblock();
var graphResponse = Meteor.http.call("GET", "https://graph.facebook.com/v2.5/me/friends", {
params: {
access_token: Meteor.user().services.facebook.accessToken
}
});
// Save user's list of friends.
Meteor.users.update(Meteor.userId(), {$set: {"profile.listOfFriends": graphResponse.data.data}});
return graphResponse;
},
...
});
What is the best way, in Meteor, to bind the friend object (with id, name, ... attributes) to the DOM and then get these attributes, such as friend ID, back once a selection is made by user?
I'm not sure if Meteor makes this any easier, but you could use data attributes to store extra information about your friend objects in the HTML element.
To save:
<li class="list-group-item" data-friend-id="{{id}}">{{name}}</li>
To retrieve:
var friendId = $(li).data('friendId');