Simple ToDo App using Agility.js with Persistence - javascript

I created a database called agilityjs that has a table called todolist. I created a file in /api/todolist.php which will act as a web service. I want to make it so when the user clicks "New Item," it will add a new item to my database by calling the PHP file (todolist.php). My next goal is to edit the item when they click to edit and delete when they click to delete.
Can anyone help me in the right direction? I have seen the persistence documentation at http://agilityjs.com/docs/docs.html#persist but I'm not sure how to apply it.
The following code is simply taken from http://agilityjs.com/ (at the bottom, you can see it and it's live demo).
Here is another good resource for learning https://gist.github.com/3166678, but I can't seem to apply it either.
//
// Item prototype
//
var item = $$({}, '<li><span data-bind="content"/> <button>x</button></li>', '& span { cursor:pointer; }', {
'click span': function(){
var input = prompt('Edit to-do item:', this.model.get('content'));
if (!input) return;
this.model.set({content:input});
},
'click button': function(){
this.destroy();
}
});
//
// List of items
//
var list = $$({}, '<div> <button id="new">New item</button> <ul></ul> </div>', {
'click #new': function(){
var newItem = $$(item, {content:'Click to edit'});
this.append(newItem, 'ul'); // add to container, appending at <ul>
}
});
$$.document.append(list);
Thank you.

Related

Summernote - Custom dropdown for ordered and unordered list

I am using Summernote editor v0.8.9 for quite a long time. I have created a custom dropdown button for Ordered List and Unordered List by using below code
let orderedList = function (context)
{
let ui = $.summernote.ui;
// create button
let button = ui.buttonGroup([
ui.button({
className: 'dropdown-toggle',
contents: '<i class="fa fa-list-ol"/><span class="note-icon-caret"></span>',
container: false,
tooltip: 'Ordered List',
data: {
toggle: 'dropdown'
}
}),
ui.dropdown({
className: 'dropdown-style',
contents: "<ol style='list-style-type:none' class='ordered-list'><li data-value='1'>1</li><li data-value='1' style='display: none;'>1)</li><li data-value='I'>I</li><li data-value='A'>A</li><li data-value='a)' style='display: none;'>a)</li><li data-value='a'>a</li><li data-value='i'>i</li></ol>",
callback: function ($dropdown) {
$dropdown.find('li').each(function () {
$(this).click(function() {
selectedListType = orderedListMap[$(this).attr('data-value')];
$(context).summernote('editor.insertOrderedList');
});
});
}
})
]);
return button.render(); // return button as jquery object
};
And also I get the dropdown attached to the toolbar as shown in the image
I have changed some code in the summernote.js to change the list style type after clicking on the dropdown item.
I am adding following code in the Bullet.prototype.wrapList method as follows
//for bullets and numbering style
if (selectedListType != 'NA') {
listNode.setAttribute('style', 'list-style-type:' + selectedListType);
}
I have also added the following code in the method "function replace(node, nodeName)" of "dom" object.
//for bullets and numbering style
if ((nodeName == 'OL' || nodeName == 'UL' ) && selectedListType != 'NA') {
$(newNode).css('list-style-type', selectedListType);
}
When I click on the dropdown item I am calling below code.
$(context).summernote('editor.insertOrderedList');
At first instance everything is working fine. I can change ordered list to unordered list as well as to other types of lists. But the problem arises when I am trying to create a new list. When I try to create a new list below the existing list (note : after double entering new line, existing list closes, hence a new list is created after double entering new line),
the focus does not stay on the current line. Instead it goes to the old list and old list style (Ordered/unordered) is getting changed.
I have also kept the default UL/OL in the toolbar for deugging and I can see that the document.selection() in the method WrappedRange.prototype.nativeRange is giving proper selection for default UL/OL but is giving wrong selection for my dropdown UL/OL.
Please help.
Let me know if any info is needed from my side
I solved this problem.
The problem was with the custom dropdown I created.
The dropdown needs to be in the following structure in the 'contents' attribute inside 'ui.dropdown'
<li>
</li>
<li>
</li>
'a' tag inside 'li' tag

Link two elements, store them, and send them to remove function - Pure Javascript

I have a little Pure Javascript prototype demonstrating shopping cart functionality.
I have a Button which adds the item to the cart (and toggles to an ON state) and then a Card which represents the item in the shopping cart.
So far I have worked;
Attach data to Add to Cart Button ✓
Send data from Button to Shopping Cart and create new Item Card ✓
However, I cannot work out how to link Button and newly created Item Card so I can:
Remove Item Card and toggle button OFF or
Toggle button OFF and remove the correct Item Card
https://codepen.io/rhysyg03/pen/PdyyWE
Your help would be much appreciated.
FYI - this is just for a demo so it doesn't need to be production ready code.
Thank you.
const shoppingCartEl = document.querySelector('#js-shopping-cart');
const addToCartButton = document.querySelector('#js-add-to-cart');
var buttonToggle = false;
var itemOneData = {
name:'Shoes',
price:"$105.00"
}
function addItem(button, itemData) {
console.log("ADD");
// var itemEl = createElement('<div class="item-card"></div>');
const itemEl = document.createElement("div");
itemEl.classList.add("item-card");
itemEl.innerHTML = itemData.name + itemData.price + "<button id='js-item-cart-remove'>Remove</button>";
shoppingCartEl.appendChild(itemEl);
const itemCardRemove = document.querySelector('#js-item-cart-remove');
itemCardRemove.addEventListener('click', () => {
removeItem();
})
}
function removeItem() {
console.log("REMOVE");
// how to do this part
}
addToCartButton.addEventListener('click', () => {
if (buttonToggle == false) {
addItem(addToCartButton, itemOneData);
buttonToggle = true;
addToCartButton.innerHTML = "Remove from Cart";
} else {
// How to do this part
removeItem();
buttonToggle = false;
addToCartButton.innerHTML = "Add to Cart";
}
})
(I am sorry I am tired a bit, you should read the very ending, firstly)
You should have items like this:
var itemOneData = {
id: 1,
name:'Shoes',
price:"$105.00"
}
var itemTwoData = {
id: 2,
name:'Shoes',
price:"$105.00"
}
Then you should store identifier on the item card element:
...
itemEl.classList.add("item-card");
itemEl.setAttribute("data-item-id", itemData.id)
...
After this, when clicking on remove button, you should:
Get the id of item to be removed itemEl.getAttribute("data-item-id")
Pass the id to remove function removeItem(id)
(this was where I've given up) Find the item with the attribute "data-item-id" having value of the id and replace it to empty string ""
There is another solution, probably far less complex: when clicking on remove button simply find it's parent and replace it with empty string.
This is a quick solution, just to get what you are looking for, but of course, maybe you should be having some 'state' where you have your cart items, and render the UI based on that state. In this quick solution, what I am doing is event delegation, as we know that the one element that will exist at the beginning is the cart div. So we place the event on this element and then check which element are we clicking, and also doing some check so we assure only that an item-card can be deleted. codepen.io/anon/pen/WgaYxe?editors=1011
Hope this helps and if you need more details please feel free to ask!
Bye

Highlight single element in ng-repeat

following problem:
I am using ng-repeat to generate a list of items. If the user clicks on a special marker on my webpage above, the following function receives an event an scrolls down to the corresponding item. In addition to scrolling down I would like to highlight the item until the user moves the mouse again. My problem ist that do to this I need to manipulate the css class of one single element of my ng-repeat list. I thought it might be possible because every ng-repeat element gets its own local scope...but I don't find the solution.
Part of my directive:
//if a marker is clicked, the following code should bring the user to the corresponding item
$rootScope.$on("Scroll_to_product", function (event, args) {
product.gotoElement(args);
});
/*function which takes the class id of an html element as argument and brings
the user to the corresponding product*/
product.gotoElement = function (args) {
var elementID = 'product-' + args;
$location.hash(elementID);
// call $anchorScroll()
$anchorScroll();
}
Any help would be great,
Thanks, Hucho
I think this woking Plunker example may help you
Plunker link
$scope.idSelectedVote = null;
$scope.setSelected = function(idSelectedVote) {
$scope.idSelectedVote = idSelectedVote;
console.log(idSelectedVote);
}
.selected {
background-color: red;
}
<ul ng-repeat="vote in votes" ng-click="setSelected(vote.id)" ng-class="{selected : vote.id === idSelectedVote}">
</ul>
it almost broke my head, but finally was easy:
product.highlightFeature = function (args) {
var id = '#'+ 'feature-' + args;
var myEl = angular.element( document.querySelector( id ) );
myEl.addClass('feature-highlight');
};
It is easy and fast..; yet thanks for your help.
This might help others...
Best
Hucho

How to add multiple items to context menu in Kendo Scheduler?

"kendoContextMenu" is one of control from Telerik suit. I am trying to attach it with Kendo Scheduler control.
Below is the code to render scheduler and menu
Part of it taken from Kendo sample site
<div id="example">
<div id="scheduler"></div>
<ul id="contextMenu"></ul>
</div>
Here is Context Menu Initialization
$("#contextMenu").kendoContextMenu({
filter: ".k-event, .k-scheduler-table td",
target: "#scheduler",
select: function(e) {
var target = $(e.target);
if (target.hasClass("k-event")) {
var occurrenceByUid = scheduler.occurrenceByUid(target.data("uid"));
} else {
var slot = scheduler.slotByElement(target);
}
},
open: function(e) {
var menu = e.sender;
var text = $(e.target).hasClass("k-event") ? "Edit Title" : "Block";
menu.remove(".myClass");
menu.append([{text: text, cssClass: "myClass" }]);
}
});
});
The above code adds only ONE item in context menu and click event directly fires up. I would like to have multiple items in a context menu and each should have its own event so that I can use them as it clicked.
Below image shows right click behavior, where it shows only Block in a menu
I am trying to get menu as below- which has multiple items and have its own click events
I am trying like below by appending text but it's seems to be wrong way to do and it can not have separate click event.
open: function(e) {
var menu = e.sender;
var text = $(e.target).hasClass("k-event") ? "Edit event" : "Add Event";
text = text + "|" + "Cancel"
menu.remove(".myClass");
menu.append([{text: text, cssClass: "myClass" }]);
}
Kindly help
I'm afraid you're appending it wrong. By concatenating "| Cancel" you're not adding a new item, but adding text to the existing one.
Try creating a new object and append it with append():
menu.append([{text: "Cancel", cssClass: "cancel-opt" }]);
Then you check by the class inside the select event:
if (target.hasClass("cancel-opt"))

jQuery - remove li from array with delete image

I'm attempting to make a menu bar that can have <li> elements added and removed. So far so good, but when I try and remove them I'm running into issues. I've toyed with this for a couple hours and now I'm wondering if this whole process could just be made easier (maybe an object?).
Anyways, here's the full code (80 lines), with comments to follow along.
var tabs = $('.accountSelectNav');
var titles = [];
var listItems = [];
// when the page loads check if tabs need to be added to the ul (menu bar)
$(document).ready(function(e) {
if ($.cookie('listItems') != null) {
console.log('not null');
//return "listItems" to it's array form.
listItems = JSON.parse($.cookie('listItems'));
$('.accountSelectNav').append(listItems);
}
});
$('.selectTable td:first-child').on('click', function(e) {
$('#home_select').removeClass('navHighlight');
//grab the text value of this cell
title = $(this).text();
$.ajax({
url:'core/functions/getAccountId.php',
type: 'post',
data: {'title' : title}
}).fail (function() {
alert('error');
}).done(function(data) {
accountId = $.trim(data);
// store values in the cookie
$.cookie('account_id', accountId, {expires : 7});
$.cookie('title', title, {expires : 7});
window.location = ('home_table.php');
});
// make sure the value is NOT currently in the array. Then add it
var found = jQuery.inArray(title, titles);
if (found == -1) {
titles.push(title);
addTab();
}
// make sure the value is NOT currently in the array. Then add it
found = jQuery.inArray(title, listItems);
if (found == -1) {
addListItem();
//place <li>'s in cookie so they may be used on multiple pages
$.cookie('listItems', JSON.stringify(listItems));
};
});
$("body").on("click", ".deleteImage", function (e) {
var removeTitle = $(this).closest('li').find('a').text();
var removeItem = $(this).closest('li')[0].outerHTML;
//remove title from "titles" array
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
//remove <li> from "listItems" array
listItems = jQuery.grep(listItems, function (value) {
return value != removeItem;
});
// this shows the <li> is still in the listItemsarray
console.log(listItems);
// put the array back in the cookie
$.cookie('listItems', JSON.stringify(listItems));
removeTab(this);
});
$("body").on("mouseover", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').show();
});
$("body").on("mouseleave", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').hide();
});
function addTab() {
tabs.append('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
};
function removeTab(del) {
$(del).closest('li').remove();
}
function addListItem() {
var s = ('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
listItems.push(s);
}
So you see I have two arrays of equal length that should always be the same length. One stores the title to be displayed in the tab, the other holds the html for the <li> which will be appended to the <ul>. I have no problem removing the title from its array. However removing the <li> from it's array is becoming a rather big hassle. You see when I get the <li> element after its been inflated the html inside does not exactly match what was put in, the browser adds style elements.
Example, the variable "removeItem" represents the html value of the selected <li> I wish to remove. It looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage" style="display: inline;"></li>
yet the value in my array "listItems" looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage"/></li>
So my attempt at removing it from my array always fails because they aren't a perfect match.
Now my question is how do I remove this <li> item? Also is there an easier way to do this whole process and I'm just not seeing it?
Thanks for your time.
EDIT
Fiddle by request here
Easiest way I can explain it.
Click the link to the fiddle.
Click any cell in the "App Name" column
This will add a <li> to the <ul> (menu) above of the table
When you hover over the <li> a picture appears
Click the picture
This should remove the <li>, both from the <ul> and from the array listItems
right now it does not
In the process of making this easier to check, I've taken your JSFiddle and did the following:
removed extra console.log and comments
removed interaction with cookies (since I did not have them in the first place, I figured they wouldn't just the first scenario)
After doing so I reached a point (you can see it here) where the desired functionality just works.
I even went ahead and removed the ajax stuff because that alert was driving me crazy. (here)
Since this works fine, my guess is that your issue lies between the lines that I removed.
Your usage of cookies is as follows:
To load existing tabs and add them back again
To save account_id and title, which is not used back again
To persist the listItems after a new item has been added
I then opened up the console with your version of the fiddle and the execution of javascript stops at $.cookie() with the error undefined is not a function.
This clearly indicates that the issue present in the Fiddle is that jQuery.cookie is not present and so those calls are halting the execution of the rest of your script. This also explains why it just started working when I took them out.
I posted the whole process of how I got there to indicate how I trimmed down the problem to specific parts, which is useful to reduce the problem space. When you're out of options and reach a place when you're lost, it's easier to post a question with less code and the specific part of the problem that you've identified. This will help you in finding the issues that you're facing and StackOverflow to provide proper answers to your questions.
Hope it helps!
Here is the solution I came up with. It should be much easier for people to understand than my original post. Although it's a long read it may be worth it, especially for new developers.
The point of this code is to make a menu bar out of an un-ordered list or <ul>. The menu bar needs to be used on multiple pages. So I'll be using cookies.
I start with this code to get a text value from my table.:
$('.selectTable td:first-child').on('click', function(e) {
// This value will be used later for the name of the tab or `<li>` inside our menu bar or `<ul>`
title = $(this).text();
});
Then I place the value in an array. I do this only if the array does not already have this string inside it. I do not want duplicates:
var found = jQuery.inArray(title, titles);
var titles = [];
if (found == -1) {
titles.push(title);
}
Then I store the array into a cookie, using a library like this:
$.cookie('titles', JSON.stringify(titles));
Now when any page loads that needs this menu bar I run this code to check if there are any values:
$(document).ready(function() {
if ($.cookie('titles') != null) {
titles = JSON.parse($.cookie('titles'));
}
});
Now I need to loop through the array. When I loop through the array I have to do 3 things:
1) Grab the string value.
2) Add the html to my new string so it becomes a list item or <li>.
3) Append the newly created <li> to our <ul>.
Like so:
for(var i = 0; i < titles.length; i++) {
var str = titles[i];
var listItem = '<li class="navHighlight">'
+ '<a href="#">'
+ str
+ '</a>'
+ '<a href="#">'
+ '<img src="images/delete.png" class="deleteImage"/>'
+ '</a>'
+ '</li>';
$('.accountSelectNav').append(listItem);
}
Now, if I want to remove this <li> I click the delete image found inside our <li>. What delete image you say? Look at the html I added again. You will see I add an <img> tag in there.
Now delete like so:
$("body").on("click", ".deleteImage", function (e) {
// grabs the text value of my li, which I want to remove
var removeTitle = $(this).closest('li').find('a').text();
// runs through my titles array and returns an array without the value above
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
});
Then I simply place the new array inside my cookie once again. Like this:
$.cookie('titles', JSON.stringify(titles));
And finally I remove the tab like this:
removeTab(this);
function removeTab(del) {
$(del).closest('li').remove();
}
Yay, I'm done. So now, if anyone has a more elegant way of accomplishing this I'm listening. I have no doubt there's a better way, javascript/jQuery isn't even close to my strong point.
The full code can be found here.

Categories

Resources