Last item removed in AngularUI connected sortable - jquery-ui

In Angular, I have multiple columns containing blocks. The columns are repeated with ngRepeat and also the blocks inside the columns are repeated. With Angular-UI and jQueryUI I made the blocks sortable and connected all columns. This works fine, I can drag blocks between columns, but only if I drag a block to the end of a non-empty column, this last (the new) block is not diplayed. However if you log the underlying array in the console, you can see that this array has updated to the blockmove. Also other watches are still called and display the correct value (as seen in the fiddle)
HTML:
<div ng-app="foo" ng-controller="bar">
<div ng-repeat="column in columns" id="column-{{$index}}" class="column">
<div class="blocks-wrapper" ui-sortable="columnSortableConfig" ng-model="column.blocks">
<div ng-repeat="block in column.blocks" class="block" id="block-{{block.id}}">
{{block.id}}
</div>
</div>
</div>
{{columns}}
</div>
Javascript:
foo = angular.module('foo', ['ui.sortable']);
foo.controller('bar', function($scope){
$scope.columns = [{blocks: [{id: 1},{id: 2}]},{blocks: [{id: 3}]}];
$scope.columnSortableConfig = {
connectWith: '.blocks-wrapper',
placeholder: 'block-placeholder',
forcePlaceholderSize: true,
tolerance: 'pointer',
};
});
I searched around on the web, made the items in the array non-primitives (link) and wrapped the callbacks of jQuery in scope.$apply() (link) but it all didn't work.
JSFiddle: http://jsfiddle.net/C5pKc/10/
(To reproduce, drag block 3 under block 2)

Are you using angular 1.2.x? If so, make sure you are using the angular1.2 branch of angular-ui/ui-sortable. Here is the source file.
The problem is described in this pull request.
In short, angular uses html comments to track ng-repeat items. Jquery does not care about comments. So when you drag things between lists, the comments get messed up and ng-repeat gets confused. Hope this helps!

Related

Jquery Mobile Javascript not working on ajax load

Have the following markup in my html page to toggle a search bar based on if a search icon is clicked:
<a id="searchIcon" href="/"></a>
<div id="searchWrapOuter" style="display:none;">
<div id="searchWrapInner">
<div id="formContainer">
<form id="searchForm" action="#">
<div>
<input type="search" name="search-mini" id="search-mini" value="" data-mini="true" />
</div>
</form>
</div>
</div>
</div>
Width the following javascipt/jquery:
$(function() {
$(document).on("click", "#searchIcon", function () {
var searchWrapper = $("#searchWrapOuter");
$(searchWrapper).slideToggle();
return false;
});
});
This code works as expected on a page load direct off a Url. When coming into the page off a link which is Ajax loaded, loads the contents of the page into the DOM, and the DOM ready handler only executes for the first page.
I have read about using the
$(document).on('pageinit'), not $(document).ready()/$(function()
I still haven't been able to get this to work when coming in off an ajax link however. What would be the correct way to implement these events to get the code to work coming in from an Ajax link?
Thanks,
Most likely it is because you are using IDs instead of classes. jQuery Mobile doesn't work well with IDs because it caches pages into the DOM so if you open a page, close it, then go back to the page, you might have your page twice inside the DOM (one visible, one hidden/cached). So when you do $("#searchWrapOuter") you don't know which element you are actually dealing with (in your case, probably the hidden one).
The solution is to change your IDs to classes. This is not very intuitive but I found that is the best way to work with jQuery Mobile.
Also note this comment in the doc which might also be relevant to you:
The id attribute of all your elements must be not only unique on a given page, but also unique across the pages in a site. This is because jQuery Mobile's single-page navigation model allows many different "pages" to be present in the DOM at the same time. This also applies when using a multi-page template, since all "pages" on the template are loaded at once.
http://jquerymobile.com/demos/1.2.0/docs/pages/page-anatomy.html
You can manually adjust delay time to 500ms and 1s.
$(searchWrapper).delay(1000).slideToggle();
My issue is that the page id was below the pages tags. So once I moved the page div above it, the javascript was included in the ajax page load. Previous to this

Knockout, JQMobile, and generating a collapsible-set doesn't quite seem to work right

I've checked out a number of samples, but none are quite the same as what I'm trying to do.
What I've got works, mostly, but it doesn't quite work right.
Here's a fiddle to illustrate the issue.
http://jsfiddle.net/5yA6G/4/
Notice that the top set works fine, but it's statically defined.
The bottom set (Tom, steve, bob) "work" basically, but the header element ends up both in the collapsible header AND in the portion of the collapsible that gets hidden.
Seems like I must be doing something wrong, but I haven't been able to figure out what.
Any ideas?
Just for reference and for anyone else running into this problem, it turns out to be at least somewhat obvious in hindsight.
Knockout's built in "anonymous" templating works great in many cases, but with JQMobile, it can be a tad quirky.
That's because JQMobile will adjust the content of the anonymous template when the page loads, just as it does with all the other content.
Then, later, when you use knockout's ApplyBindings function, knockout will add the applicable elements, just as it should. As many posts and answers have hinted at, you then MUST call collapsible() on the newly created elements, via something like this.
$("div[data-role='collapsible']").collapsible({refresh: true});
No problem there. HOWEVER, if JQM has already applied formatting, then the anonymous template has already been "rendered" by JQM, so rendering it again by calling collapsible causing all sorts of funky results, including doubled heading, nested collapsibles, etc.
The solution for me was to use Knockout's "Named Template" feature, and just put the template to render the collapsible elements into a tag, like this:
<script type="text/html" id="alarm-template">
<div data-role="collapsible" data-collapsed="true" data-collapsed-icon="arrow-d" data-expanded-icon="arrow-u" data-enhance="false">
<h3 data-bind="text:name"></h3>
<p>The content here</p>
<p data-bind="text: name"></p>
</div>
</script>
Doing this prevents JQM from "rendering" the template elements when the page loads, so they'll be rendered properly when they're actually generated.
EDIT: The above works fine for collapsibles NOT in a collapsible-set, but, if they're in a set, I've found the styling of the elements (particularly, the corner rounding to indicate belonging to a set) doesn't work right.
From what I can tell, there are 2 problems:
The first is that just triggering "Create" doesn't actually refresh the styling of all the collapsibles in the set. to do that you have to do...
$("div[data-role='collapsible-set']").collapsibleset('refresh');
But, there's a worse problem. JQM "marks" the last item in the set as the "last item". That fact then gets used to determine how to style the last item as it's being expanded/collapsed.
Since Knockout doesn't actually rebuild the entire set (for speed), each time you call the refresh method, JQM dutifully marks the last item as "last", but never removes the marks on previous items. As a result, if you start from an empty list, EVERY item ends up being marked "last" and the styling fails because of this.
I've detailed the fix for that at github in an issue report.
https://github.com/jquery/jquery-mobile/issues/4645
I actually found a much easier way to do this:
Set up your foreach binding as you normally would for me it looked like this
<div data-bind="foreach: promotions">
<h3 data-bind="text: Title"></h3>
<p>Creator:<span data-bind="text: Creator"></span></p>
<p>Effective Date:<span data-bind="text: EffectiveDate"></span></p>
<span data-bind="text: Description"></span>
<a data-bind="text: ButtonText, attr: {href: ButtonLink}"></a>
Wrap that in a div with class="collapsible like so
<div data-role="collapsible-set" data-bind="foreach: promotions">
<div class="collapsible">
<h3 data-bind="text: Title"></h3>
<p>Creator:<span data-bind="text: Creator"></span></p>
<p>Effective Date:<span data-bind="text: EffectiveDate"></span></p>
<span data-bind="text: Description"></span>
<a data-bind="text: ButtonText, attr: {href: ButtonLink}"></a>
Apply the collapsible widget via jquery mobile after you do your binding like so:
$(document).ready(function () {
ko.mapping.fromJS(data, dataMappingOptions, PromotionViewModel.promotions);
ko.applyBindings(PromotionViewModel);
$('.collapsible').collapsible();
});
For a collapsible set the same idea can be applied just set the class="collapsible-set" on your foreach div. Hope this helps

jQuery Mobile Losing Style After Updating DOM

A question similar to this has been posted several time, but I cannot find a solution that works. Hopefully, someone can help!
I am using jQuery Mobile 1.1 and jQuery 1.7.2, so I'm on the most recent stable releases. I want to create a dynamic page header. Using this HTML code, it works fine:
<div data-role="page" id="levela">
<div data-role="header" id="hdr_levela">
<h1>Title</h1>
</div>
</div>
So I then go to dynamically create the title. I change the HTML to this:
<div data-role="page" id="levela">
<div data-role="header" id="hdr_levela">
</div>
</div>
And added the following jQuery code:
// Set the header
var dirHeader = $('#hdr_levela');
dirHeader.append('<h1>' + title+ '</h1>');
The title appears, but is not styled. I have found several posts about this. In the jQuery Mobile Documentation, it says:
"However, if you generate new markup client-side or load in content via Ajax and inject it into a page, you can trigger the create event to handle the auto-initialization for all the plugins contained within the new markup. This can be triggered on any element (even the page div itself), saving you the task of manually initializing each plugin (listview button, select, etc.).
For example, if a block of HTML markup (say a login form) was loaded in through Ajax, trigger the create event to automatically transform all the widgets it contains (inputs and buttons in this case) into the enhanced versions. The code for this scenario would be:
$( ...new markup that contains widgets... ).appendTo( ".ui-page" ).trigger( "create" );
So I tried several things. After the above code, I added the following:
dirHeader.trigger("create");
This had no effect. So I tried to put it on the actual append itself:
dirHeader.append('<h1>' + folderName + '</h1>').trigger("create");
This had no effect. I then tried the process on the parent element (in this case, the id of the parent div is "levela"). So I tried this:
$('#levela').trigger("create");
This also had no effect. At this point, I am completely lost. Every solution involves doing one of the things I have tried and is just not working. I must be missing something incredibly basic but I just can't seem to find it.
Thanks in advance for your help!
You can update the content by calling .page:
See this working Fiddle Example!
// Set the header
var title = 'super hyper BuBu',
$dirHeader = $('#hdr_levela');
$dirHeader.append('<h1>' + title+ '</h1>').page();
I just solved a similar problem -- it appears that jQM headers and footers do not have the "create" method, so as far as I can tell, the css classes and roles need to be added manually.
For reference, I posted an example fix on this (old) question: JQuery Mobile trigger('create') command not working

Using jQuery UI Accordion with program-generated HTML

I am trying to create a JQuery UI Accordion, but with the HTML within an accordion being generated by some jQuery code.
I also have some example accordion items in the base HTML; these are working fine.
The problem is that the (sample 1)
$(function(){
$("#accordion").accordion({
event: "click hoverintent"
});
});
code puts accordion-specific class, role etc. tags into the
<div id="accordion">
<h3>Heading</h3>
<div>
<p>
Stuff
</p>
</div>
...
tags, but these are not being inserted into the HTML code I generated with jQuery.
The items above '...' are working fine.
Similar tags generated by jQuery below the '...' do not work, as they don't receive the accordion tags.
I guess the problem lies in when to call the (sample 1) code, so that it is executed after my HTML has been generated. At present it is in the head of my page, as with the accordion examples. I have tried it in other places, and also tried but without success.
Any suggestions, please?
You need to destroy then recreate the accordion for it to be able to work with appended items.
Here is a demo

jQueryUI nested accordion only working on first sub-list

I'm working on a site that has a dynamically generated FAQ and I'm trying to get nested accordions working. The problem is, only the first collection of questions take on the ui-accordion class.
Here's my code:
http://jsfiddle.net/SmFdt/
(I just copied the source of the page and stripped out most of the text)
What am I doing wrong?
You've got the same id assigned to multiple divs. Try the following instead:
HTML
<h1>Frequently Asked Questions</h1>
<div id="faqs-container" class="accordian">
<h3>One</h3>
<div class="accordian">
<h3>A</h3>
<div>AAAAAAAAAA</div>
<h3>B</h3>
<div>BBBBBBBBBB</div>
</div>
<h3>Two</h3>
<div class="accordian">
<h3>A2</h3>
<div>AAAAAAAAAA2</div>
<h3>B2</h3>
<div>BBBBBBBBBB2</div>
</div>
</div>
JavaScript
$("div.accordian").accordion({
autoHeight: false,
collapsible: true,
active: false
});
Link to example: http://jsfiddle.net/SmFdt/1/
Try this http://jsfiddle.net/SmFdt/3/
The reason it was not working was you were using the same id for multiple divs. I have changed the ids to classes.
On a side note, you have lot of code to display the accordion. You may possibly want to consider reducing some code. (e.g. no need of <p> inside <div>. You can control the spacing using CSS margin and padding properties.)

Resources