jstree Nodes to edit a value - jquery-plugins

I'm building a jstree whose node titles are made of product categories (say 'cars'), and that contain, besides that title ('cars'), an input box (modifiable) with the price, and three buttons which sending commands to the server and some JS on the client, can perform 'delete','save' and 'add new' functions. (i'd put a picture of the layout but dont think it adds much to the clarity of the question, but let me know).
Since I'm using JSON plugin and pulling the tree from a database, I'm sending the data from server and, so far, I've managed to add the html to the data. That renders the layout I want, but since everyting is inside an tag, I have nasty problems when, for instance, I click on the input box (i.e.: the screen goes to top), or when I try to catch the click event on the buttons.
Can someone, please, point me in the right way of doing this with jstree? I've been crawling over forums and docs for over 3 days now, and start to believe my brain has cooked up some time ago and just noticed it. :)
Some (summarized and "pseudoized") code:
class NewNode
{
var $data;
var $attr;
var $state;
var $children;
var $metadata;
}
and later on...
$NNode = new (NewNode);
$NNode->data = 'the-price-category-from-my-database'; <-- pretty much pseudo code here...
$NNode->attr['value'] = 'the-price'; <-- pretty much pseudo code here...
$htm = "<div style='position:relative; width:400; float:left;'>";
$htm .= "<div style='float:left; font-weight:bold; width:250px;'>";
$NNode->data = $htm . $NNode->data;
$NNode->data .= "</div>";
$NNode->data .= "<div style='width:100px; float:left; text-align:right;'>";
$NNode->data .= "$<input type='text' value='" . $NNode->attr['value'] . "'width='20%' style='width:50px; text-align:right;'/>";
$NNode->data .= "<button class='btn_save_price'> </button>";
$NNode->data .= "<button class='btn_new_price'> </button>";
$NNode->data .= "<button class='btn_delete_price'> </button>";
$NNode->data .= "</div>";
$NNode->data .= "</div>";
$MyTree->children[] = $NuevoNodo;
And that's it...
die(json_encoed($MyTree))
Thanks again.

firstly- welcome to SO. When posting a code snippet please use the code tags to format your code.
also I do think that a screenshot would help clarify things.
to your question- I think that placing controls such as textboxes, buttons etc. inside tree nodes is not really standard.
consider using a different panel for those controls (see attached image (details deleted to avoid propriety issues) of the way I use jsTree for editing).
Also- when you create the JSON data on the server side, you create a tight coupling between your chosen jQuery plugin and your server side code.
That means that if you decide to switch from jQuery to a different framework, or even switch from jsTree to a different plugin- your server code would have to change.
Ideally, you'd like the changes in the UI to be limited to the UI layer.
What I do in my project, is retrieve regular objects from the server side, and convert them to jsTree format on the client side. That way, if anything changes on the UI side, only the js code would have to change.

Related

How to set Checkbox by default checked in treeview

I am trying to set treeview with checkbox and there are some check box are by default checked , here my data source value:-
[{"id":12,"Name":"Shirts","hasChildren":false,"Checked":true}
,{"id":13,"Name":"Jeans","hasChildren":false,"Checked":false},
{"id":14,"Name":"Shoes","hasChildren":false,"Checked":true},
{"id":15,"Name":"Apparel accessories","hasChildren":false,"Checked":false}]
and my view page code:--
$(document).ready(function() {
$("#category-treeview").kendoTreeView({
dataSource: categories,
dataTextField: "Name",
checkboxes: true
});
});
but i no one checkbox is selected why?
Can any advice how to solve this?
Regards,
vinit
Your code is basically correct. The only problem is that Checked needs to be checked (lowercase). Your data would look like:
var categories = [
{"id":12,"Name":"Shirts","hasChildren":false,"checked":true},
{"id":13,"Name":"Jeans","hasChildren":false,"checked":false},
{"id":14,"Name":"Shoes","hasChildren":false,"checked":true},
{"id":15,"Name":"Apparel accessories","hasChildren":false,"checked":false}
];
I put your code with this small change here: http://jsfiddle.net/OnaBai/78k2b/
If all you need to do is show whether the checkbox is checked or not, you can easily employ a templateFunction for the checkbox.
checkboxes: {
template: checkboxTemplate
}
And use a function something like
function checkboxTemplate(e) {
if(e.item.Checked) {
return "<input type='checkbox' checked='checked' />";
}
else {
return "<input type='checkbox' />";
}
}
The issue with this approach, is there isn't a two-way data-binding happening. So if you change a checkbox, and them dump the dataSource, that change isn't reflected.
If you are needing two-way data-binding, so you can post the changes back, you will need to employ something quite a bit more complicated. It is laid out pretty well in this SO post (Binding checkboxes in treeview with checkboxes that uses remote datasource).
I have looked for a more elegant answer to this, as it would seem fairly common, but haven't found anything yet.

Is it possible to implement a circular/infinite carousel using owl carousel? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am using owl carousel and it works perfectly except it does not support circular/infinite scrolling. I did search for ideas on google and stackoverflow with no luck. Has anyone implemented circular/infinite scrolling in owl carousel?
Owl Carousel does have the loop: true configuration setting. But, there's a few problems I don't like:
Owl doesn't goto the first slide when at the end, when dragging (instead of clicking on navigation buttons)
Owl rewinds to the first slide, it doesn't wrap around infinitely. This is a big difference, and not nearly as pleasing as a properly circular / infinitely scrolling carousel.
To that end I've found and recommend using the Slick Carousel instead. Slick has a "Center Mode" which had exactly the functionality I was looking for:
http://kenwheeler.github.io/slick/
No.They said that carousel doesn't support circular slides.
Possibly this may help:
rewindNav: true
But this works only with navigation arrows, not with responsive slides =(
Or you may huck it somehow)
I was able to accomplish it using jquery/php/ajax. Here is how I did it:
1) First you need to initially place the first x amount of images on the page which will technically be the first page and then afterwards you'll load via ajax each time you reach the end of the carousel. In the example script I supplied I am getting a list of images from a fictional database table called "images". In my php script, for this particular example, it will return 24 owl-item divs with content. For this example I will loading 24 images at a time on the first page initially and then ajax will attempt to return 24 more each time.
HTML (You will need to add the first items into the carousel div and these items will technically be the first page of items. You could use php to populate the divs/image source for the initial first page. Just use regular divs like I did below because the carousel will add the owl-item class to them once it initializes).
<div class="circle-slider">
<div>
<img src="/path/to/image/1" />
</div>
<div>
<img src="/path/to/image/2" />
</div>
.... the rest of the images go here, each in their own div ....
.... for this example I'd load 24 images total ...
</div>
Javascript (This javascript goes on the same page as the HTML above.)
<script type="text/javascript">
$(document).ready(function() {
var itemsPerPage = 0; // The number of items per page.
var page = 2; // Start on page 2 since we initially created page 1 in HTML
var working = false; //Boolean to keep the trigger from firing while we work
var lastvalue = 0; //last value of the owl objects item position array
var carouselDiv = '.circle-slider'; // the div that you will be placing the owl carousel on. See HTML above. MUST BE IN jQuery Notation.
//Normal Owl Carousel Setup. See their site for more options. My example works with these options. No guarantee if you change them to something else that it will work.
$(carouselDiv).owlCarousel({
items : 1,
itemsDesktop : [1920,2],
itemsDesktopSmall : [980,2],
itemsTablet: [768,2],
itemsTabletSmall: [480,1],
itemsMobile : [370,1],
singleItem : false,
itemsScaleUp : false,
slideSpeed : 800,
paginationSpeed : 300,
rewindSpeed : 250,
pagination:false,
autoPlay : false,
afterMove : function() {
// This is where all the magic happens. Once you slide the items around and let go this afterMove callback fires.
var owl = $(carouselDiv).data('owlCarousel'); //get the current owl carousel object
lastvalue = owl.positionsInArray[owl.positionsInArray.length-1]; //Get the last item position value in the position array
if((owl.currentItem == owl.maximumItem) && !working){
working = true; //Set working to true so we dont fire more events and load more items until this request is finished working
$.ajax({
method: "GET",
url: "/path/to/php/script/see/script/below",
async: false,
dataType: "script",
data: { page: page, itemWidth: owl.itemWidth }
}).done(function( data ) {
itemsPerPage = parseInt(cresults.numberOfItems, 10);
if( itemsPerPage ){
$('.owl-wrapper').width($('.owl-wrapper').width() + (itemsPerPage * owl.itemWidth)); //modify the width of the wrapper div to handle the new items
$('.owl-wrapper').append(cresults.html); //append the markup
owl.maximumItem = parseInt(owl.maximumItem, 10) + parseInt(itemsPerPage, 10); //modify the max items in the owl object
for (var i = 0; i < itemsPerPage; i++) { // add new indexes in the position array for the owl object.
lastvalue = lastvalue-owl.itemWidth
owl.positionsInArray.push(lastvalue);
}
owl.maximumPixels = owl.maximumPixels - (owl.itemWidth * itemsPerPage); //modify the owl maximum pixels to accomodate new items
owl.$owlItems = $(carouselDiv).find(".owl-item");
page = page + 1;
}
working = false;
});
}
}
});
});
</script>
PHP SCRIPT (Create a php file and this should be the page that is used in the ajax url in the JavaScript i.e. $.ajax({method: "GET",url: "/path/to/php/script"..... )
<?php
$page = isset($_GET['page']) ? $_GET['page'] : 2;
$itemWidth = isset($_GET['itemWidth']) ? $_GET['itemWidth'] : 0;
//Get 24 images from my database
$link = mysqli_connect("myhost","myuser","mypassw","mybd") or die("Error " . mysqli_error($link));
$query = 'SELECT * FROM images LIMIT 24 OFFSET ' . (($page - 1) * 24);
$result = $link->query($query);
$return = null;
while($image = mysqli_fetch_object($result)) {
$return .= '<div style="width: ' . $itemWidth . 'px;" class="owl-item"><div><img src="' . $image->path . '" alt="img" /></div></div>';
}
mysqli_close($link);
// Replace some characters in the return string to they wont mess up javascript
$return = preg_replace('/\n/s', "", $return);
$return = preg_replace('/\s\s+/', ' ', $return);
$return = preg_replace('/\'/', '’', $return);
echo 'cresults = { "html" : \'' . $return . '\', numberOfItems: \'' . $result->num_rows . '\'};'; //echoing the return value will fulfill the Ajax call to this method
That's pretty much it. Easy as pie. Works pretty well too. If the browser resizes and causes the owl items to resize as well, it does reset the carousel back to the first item but I figured out how to add the items to the object so it doesnt mess things up and that is already included in the JavaScript. Let me know if you have any issues and I might be able to help fix them. Been working on this several days and just got this working so I haven't had time to extensively test it but I know it works on mobile phones, both iPhone and Android and works on iPads as well as on desktop browsers. Have fun!

Auto save joomla article for client

i know its sounds a bit crazy, but so many clients have problems with not saving their article properly.
I just wanted to use a simple method to trigger the onclick of the APPLY button inside a joomla article in edit mode.
Primarily back end editing as i have a good admin template that allows me to show clients the bare bones.
I know that by clicking apply the page reloads but thats better than nothing.
How on earth do i add do this?
I was hoping something like this would work but i dont quite know how to trigger a button that seems to reside inside a toolbar function of some sort.
I have this:
<script type="text/javascript">
$(document).ready(function() {
$('??????').trigger('click');
});
</script>
What would replace the question marks?
Also i know i would need to put a timer into the jquery code but how do i get the link below to trigger?
http://mydomain.com/administrator/index.php?option=com_content&sectionid=1&task=edit&cid[]=97
In the toolbar.content.html.php file joomla has this:
class TOOLBAR_content
{
function _EDIT($edit)
{
$cid = JRequest::getVar( 'cid', array(0), '', 'array' );
$cid = intval($cid[0]);
$text = ( $edit ? JText::_( 'Edit' ) : JText::_( 'New' ) );
JToolBarHelper::title( JText::_( 'Article' ).': <small><small>[ '. $text.' ]</small></small>', 'addedit.png' );
JToolBarHelper::preview( 'index.php?option=com_content&id='.$cid.'&tmpl=component', true );
JToolBarHelper::save();
/////////////////////////////////////
JToolBarHelper::apply(); // < // THIS IS WHAT I WANT TO TRIGGER
/////////////////////////////////////
if ( $edit ) {
// for existing articles the button is renamed `close`
JToolBarHelper::cancel( 'cancel', 'Close' );
} else {
JToolBarHelper::cancel();
}
}
...... more stuff here
}
I know this might sound crazy but wouldnt it be great if autosave could happen even without a reload, but i guess that would mean posting all the data using jquery rather than the php post and reload page method.
Anyways im not expecting a miracle here but if anyone could help that would be great.
Cheers in advance
John
PS:
i just tried something like this hoping maybe it will work but it just reloads the page:
function autosave()
{
window.location = "index.php?option=com_content&sectionid=<?php echo $_GET['sectionid'];?>&task=edit&cid[]=<?php echo $row->id;?>"
}
You won't be able to do it without forcing a reload unless you decide to re-write the whole of com_content with an ajax implementation.
Looking at the code you've posted I guessing Joomla! 1.5 - which by default has MooTools 1.12 or 1.2.5 (if you enabled the MooTools upgrade plugin in later versions of 1.5.x) - so more of a question but why not use that?
You will have to modify the admin template to embed the JS you need, 1.5 has few triggers and none that are really worth using in the admin screens (unless you're up for a fair bit of PHP coding)
Somewhere in the <head> tag of com_content's Article view you will need to add this:
<script type="text/javascript">
var interval = 30 //seconds
var timer = setTimeout(submitbutton('apply'),(interval * 1000));
}
</script>
Please note I haven't tried this just typed it straight into here.
Since you're on 1.5 have you tried the Simple Content Versioning extension - it has autosave functionality that appears to be what you want - and probably works whereas who knows with my code in #3.

Re-running .getJSON on .click to return new results(jQuery/AJAX)

This is driving me crazy, but first I would like to apologize. I am very new to javascript/jquery. I did, however, do my best to solve this by searching relentlessly, and to no avail.
Here's my issue: I am implementing a Flickr photo gallery for a client b/c she insists on using it to upload her pictures. To do this I am using a slider gallery I purchased, and some jQuery/AJAX to create all the functions/requests. The slider is a jQuery script that uses specifically structured selectors to create the slideshow. The structure is like this:
<div class="slider">
<div class="slider-item">
<img src="path/to/img.jpg"/>
<img class="thumbnail" src="path/to/img_thumbnail.jpg"/>
<div class="caption">My Caption</div>
<div class="thumbnail-caption">My Thumb Caption</div>
</div>
</div>
The function I setup is like this:
var $currentPage = 1;
var $totalPages;
var $sliderHTML = "<div class='slider'></div>";
var $perPage = 18;
function flickr(){
$(function (){
$($sliderHTML).prependTo("#portfolio");
$.getJSON('http://path/to/flickr?perpage=' + $perPage + '&page=' + $currentPage + '&format=json&jsoncallback=?',
function(data){
$totalPages = Math.ceil(data.photos.total / $perPage);
$.each(data.photos.photo, function(i,item){
// Loop results and grab all variables I need - Examples omitted
// After which, append variables to string
var $sliderItem = '<div class="slider-item"><img height="' + imgHeight + '" src="' + photoURLo + '" alt="' + photoTitle + '" /><img height="75" width="75" class="thumbnail" src="' + photoURLm + '" alt="' + photoTitle + '" /><div class="caption">' + photoTitle + '</div><div class="thumbnailCaption">' + photoTitle + '</div></div>';
// Then append to the main div
$($sliderItem).appendTo(".slider");
});
});
}
// Finally call the function on document.ready
$(document).ready(function(){
flickr();
});
To make sure the slider doesn't load until the flickr function is completed (which was causing screw-ups) I just wrapped it in a function and call it on window.load. which works perfectly. And finally I initialize the slider w/ a window.load event.
$(window).load(aSlider()); // loads the slider script
$(window).load(advSlider()); // initializes the slider
The whole setup works great. Initially.
Here's the issue. I need to call more pictures and this is not working at all! Here's the code snippet in my HTML:
<script type="text/javascript">
$('#moreSlides').click(function (){
if($totalPages == $currentPage){ //checks for last page
$currentPage = 1; //resets to page one
}
else {
$currentPage++; // increments page
}
$('.slider').remove(); //removes entire slider div
flickr();
$(".slider-item").ajaxComplete(aSlider());
advSlider();
});
</script>
One way or another this always fails. I have tried stepping through this click event in the console and what it basically looks like is that it gets to the flickr() function and just passes over it instead of executing the function (which I can see happen if I step through it in the console on load). However, it does eventually execute the function... it creates the div class=slider, and within it, my loading animation, but after that it does not load the slide-items until after it executes the aSlider() function.
I have reproduced what I want to happen in the console manually and it works fine: Increment the $currentPage: check. Remove the .slider div: check. Execute flickr():check. Execute aSlider: check. Initialize advSlider(): check. Everything works perfectly with all the second page images showing up.
Something is wrong with the sequence and I simply do not know what it is. I have tried everything I can find to get the aSlider to wait, but it doesn't work. Please help!
Thanks
I ended up solving this by creating a setTimeout loop (with if statements).
function loadSlides(){
if($totalPages != $currentPage){ // Making sure we're not on the last page, which may not have the exact $perPage number
if($('.slider-item').size() == $perPage){ // See if all slides have loaded by counting number of .slider-item and comparing to $perPage variable
$('#loader').remove(); // Remove loading animation
aSlider(); // Execute Slider code
setTimeout(function(){
advSlider(); // Instantiate slider (this may not be necessary on the setTimeout here, just being safe)
},50);
}
else {
setTimeout(function(){ // If all slides haven't loaded, wait 20ms and retry the function.
loadSlides();
},20);
}
}
else {
if($('.slider-item').size() == $lastPage){ //This is the same thing as about just takes into account $lastPage instead of $perPage
$('#loader').remove();
aSlider();
setTimeout(function(){
advSlider();
},50);
}
else {
setTimeout(function(){
loadSlides();
},20);
}
}
}
This is what I had to do to make this work. I hope it helps someone b/c getJSON can't be loaded synchronously and this seems like a common issue. Although setTimeout is kind of a hack, using this will allow your code to run more quickly than putting in some generic number like some people seem to do:
$(document).ready(function(){
setTimeout(function(){
aSlider();
},1600);
});
Using setTimeout like that is terrible b/c sometimes its way too long and other times it still isn't long enough. So in order to get it to always work correctly, you have to set a terribly high timeout.
Like I said, I'm very new to all this so if anyone has a better way of writing this or doing the same time, feel free to answer!

jQuery Functions need to run again after ajax is complete

I am developing a website that parses rss feeds and displays them based on category. You can view it here: http://vitaminjdesign.com/adrian
I am using tabs to display each category. The tabs use ajax to display a new set of feeds when they are clicked.
I am also using two other scripts- One called equalheights, which re-sizes all of the heights to that of the tallest item. And the other script I am using is called smart columns, which basically resize your columns so it always fills the screen.
The first problem I am having is when you click a new tab (to display feeds within that category). When a new tab is clicked, the console shows a jQuery error:
$(".block").equalHeights is not a function
[Break On This Error] $(".block").equalHeights();
The main problem is that each feed box fills up the entire screen's width (after you click on a tab), even if there are multiple feed boxes in that category.
MY GUESS - although all of the feeds (across all tabs) are loaded on pageload, when a new tab is selected, both jQuery scripts need to be run again. any ideas on how I can make this work properly?
One thing to note - I used the ajaxSuccess method for making equalHeights work on the first page...but it wont work after a tab is clicked.
My jQuery code for the tabs are below:
$(".tab_content").hide(); //Hide all content
$("ul.tabs li:first").addClass("active").show(); //Activate first tab
$(".tab_content:first").show(); //Show first tab content
$("#cities li:nth-child(1)").addClass('zebra');
$("#column li ul li:nth-child(6)").addClass('zebra1');
//On Click Event
$("ul.tabs li").click(function() {
$("ul.tabs li").removeClass("active"); //Remove any "active" class
$(this).addClass("active"); //Add "active" class to selected tab
$(".tab_content").hide(); //Hide all tab content
var activeTab = $(this).find("a").attr("href"); //Find the href attribute value to identify the active tab + content
$(activeTab).fadeIn(); //Fade in the active ID content
$(".block").equalHeights();
return false;
});
Thanks to Macy (see answer below), I have brought my jQuery script to the following: (still does not work)
$(document).ajaxSuccess(function(){
var script = document.createElement('script');
script.src = 'js/equalHeight.js';
document.body.appendChild(script);
equalHeight($(".block"));
I found some small problems in your code. I am not sure that my suggestions will solve all the problems, but I decide to describe my first results here.
1) You should remove comma before the '}'. Currently the call look like $("#column").sortable({/**/,});
2) The function equalHeight is not jQuery plugin. It is the reason why the call $(".block").equalHeights(); inside your 'click' event handler follows to the error "$(".block").equalHeights is not a function" which you described. You should change the place of the code to equalHeight($(".block")); like you use it on other places.
3) The script http://vitaminjdesign.com/adrian/js/equalHeight.js defines the function equalHeight only and not start any actions. Once be loaded it stay on the page. So you should not load it at the end of every ajax request. So I suggest to reduce the script
$(document).ajaxSuccess(function(){
var script = document.createElement('script');
script.src = 'http://vitaminjdesign.com/adrian/js/equalHeight.js';
document.body.appendChild(script);
equalHeight($(".block"));
$("a[href^='http:']:not([href*='" + window.location.host + "'])").each(function() {
$(this).attr("target", "_blank");
});
});
to
$(document).ajaxSuccess(function(){
equalHeight($(".block"));
$("a[href^='http:']:not([href*='" + window.location.host + "'])").each(function() {
$(this).attr("target", "_blank");
});
});
4) I suggest to change the code of http://vitaminjdesign.com/adrian/js/equalHeight.js from
function equalHeight(group) {
tallest = 0;
group.each(function() {
thisHeight = $(this).height();
if(thisHeight > tallest) {
tallest = thisHeight;
}
});
group.height(tallest);
}
to
function equalHeight(group) {
var tallest = 0;
group.each(function() {
var thisHeight = $(this).height();
if(thisHeight > tallest) {
tallest = thisHeight;
}
});
group.height(tallest);
}
to eliminate the usage of global variables tallest and thisHeight. I recommend you to use JSLint to verify all your JavaScript codes. I find it very helpful.
5) I recommend you to use any XHTML validator to find some small but sometime very important errors in the markup. Try this for example to see some errors. The more you follow the XHTML standards the more is the probability to have the same results of the page in different web browsers. By the way, you can dramatically reduce the number of the errors in your current code if the scripts included in the page will be in the following form
<script type="text/javascript">
//<![CDATA[
/* here is the JavaScript code */
//]]>
</script>
I didn't analysed the full code but I hope that my suggestions will solve at least some of problems which you described in your question.
Essentially, when you add a new element to the document, the equalheights script has not attached its behavior to that new element. So, the "quick fix", is probably to re-embed the equalheights script after an ajax request has completed so that it re-attaches itself to all elements on the page, including the elements you just added.
Before this line: $(".block").equalHeights(); , add a line of script which re-embeds/re-runs your equalheights script.
$.getScript('<the location of your equalHeightsScript>');
$.getScript('<the location of your smartColumnsScript>');
$(".block").equalHeights();
or
var script = document.createElement('script');
script.src = '<the location of your script>';
document.body.appendChild(script);
A better solution would be to upgrade the plugin so it takes advantage of live. However, I'm not up to that at the moment :)
Some Error Here
$("ul.tabs li").click(function() {
$("ul.tabs li").removeClass("active"); //Remove any "active" class
$(this).addClass("active"); //Add "active" class to selected tab
$(".tab_content").hide(); //Hide all tab content
.
.
.
});
Should be re-written like this
$("ul.tabs li").click(function() {
$(this).addClass("active").Siblings("li").removeClass("active");; //Remove any "active" class Add "active" class to selected tab
$(".tab_content").hide(); //Hide all tab content
.
.
.
});
I don't think you need to run the scripts again after the ajax, or at least that's not the "main" problem.
You seem to have some problems in the script smartColumn.js
Right now it seems to only operate on the ul with the id "column" ('#column'), and it is working on the one UL#column you do have, but of course your HTML has many other "columns" all of which have the class "column" ('.column') that you want it to work on as well.
Just to get the beginning of what you are trying to do, change all the selectors in smartColumn.js that say 'ul#column' to say 'ul.column' instead, and then alter the HTML so that the first "column" has a class="column" rather than an id="column".
That should solve the 100% wide columns at least.
That should solve your "Main" Problem. But there are other problems.

Resources