Binding lost (after click) in angular js small example - ruby-on-rails

I have a very small application in Angular JS. It's placed inside a bigger rails application, but I don't see too much interaction. The angular application, allows the user to interact with a group of categories. As easy as:
var angular_app = angular.module('angular_app', []);
angular_app.config(['$httpProvider', function($httpProvider, $cookieStore) {
//Protection
}]);
angular_app.controller('CategoriesController', function ($scope, $http) {
$scope.isEditing = false;
$scope.categoryName = '';
$http.get('/api/categories').success(function(data) {
//We use this to data-bind with the HTML placed below
$scope.categories = data;
});
$scope.addNewCategory = function() {
...
}
$scope.editCategory = function(index) {
if (!index)
return;
var selectedCategory = $scope.categories[index];
// With ng-show, we make visible the part of the UI
// that should be used for editing
$scope.isEditing = true;
}
$scope.cancelEditCategory = function() {
$scope.isEditing = false;
}
$scope.deleteCategory = function(index) {
...
}
});
angular.element(document).ready(function() {
angular.bootstrap(document, ['angular_app']);
});
The idea is that the information is shown in a list, and we have an 'edit' button that allows the user to see other part of the UI that will let him perform changes.
<div ng-controller="CategoriesController">
<div ng-show='isEditing' class="popup_menu">
DIV FOR EDITING
</div>
<ul>
<li ng-repeat="category in categories">
<a href="#" ng-click='deleteCategory($index)'>[X]</a>
<a href="#" ng-click='editCategory($index)'>[E]</a>{{ category.name }}
</li>
</ul>
<input type="text" id="categoryTextBox" ng-model="categoryName"/>
<button id="submit" ng-click='addNewCategory()'>New category</button>
</div>
When I'm clicking the edit button, the corresponding part of the UI gets visible, but just after that, something happens, and the ul that should render the list, looses completely the binding, just showing something like:
[X] [E]{{ category.name }}
When it must be showing:
[X] [E]computer science
[X] [E]politics
[X] [E]news
(Which is what I have in the scope). It happens a few after the click (and works for a sec). No errors on the console, no interactions with other libraries (as far as I can see).
Thanks!

Turbolinks
I have no experience with Angular, but perhaps your problem could be to do with Turbolinks - this is a way of Rails loading the <body> tag of a page only - keeping the <head> intact.
Turbolinks is notorious for Javascript on Rails, as each time you reload your <body> without reloading the <head> part of your page, all your JS bindings are going to disappear. The solution to this, in normal JS, is to use JQuery / Javascript delegation, and delegate from the document object:
$(document).on("action", "delegated_object", function(){
...
});
Apologies if this does not work - it's a common issue for us, but as I have no experience with Angular, I don't know if it's going to help you or not.

It seems that I should have been more careful with the links:
<a href="#" ng-click='deleteCategory($index)'>[X]</a>
<a href="#" ng-click='editCategory($index)'>[E]</a>{{ category.name }}
Don't know exactly how this works, but seems that if the link has his href attribute, a GET request is made against 127.0.0.1, breaking in some way the angular code. If you put them like:
<a ng-click='deleteCategory($index)'>[X]</a>
<a ng-click='editCategory($index)'>[E]</a>{{ category.name }}
The problem will be solved. Thanks all for reading and helping!

Related

for iOS webapp <a> tags except to bootstrap modal

<script>
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
var a=document.getElementsByTagName("a");
for(var i=0;i<a.length;i++)
{
a[i].onclick=function()
{
window.location=this.getAttribute("href");
return false
}
}
}
</script>
<a href="link.php" data-target="#ajax" data-toggle="modal"><i class="fa fa-binoculars">
i use this code for iOS webapp and affect all 'a tag', but this code blocks proper operation to bootstrap modal. how can i this code except for modal?
I had an exact same issue and the solution was dead simple.
change your <a> tag to <div>. that's it.
like this:
<div href="link.php" data-target="#ajax" data-toggle="modal"><i class="fa fa-binoculars">
the script works only on <a> tag, so you can avoid the modal action by change the tag different to <a>...

Making first mobile Safari tap a 'clickable action'

I have seen variations on the theme, but no clear answer. Basically I want an AngularJS Directive that registers a click and inserts extra content into a page, and then scrolls down a bit to make the new content visible. Here is the HTML
<li class="btn btn-default" ng-show="resto.link !== 'none'">
<p scroll-down onclick="void(0)">
Full review
<span class="glyphicon glyphicon-chevron-right right"></span>
</p>
</li>
</ul>
<div class="row">
<div class="col-xs-12" ng-bind-html="fullReview">
</div>
</div>
The onlick part is an Apple suggestion, that seems not to work.
And then I have:
.directive 'scrollDown', () ->
restrict: 'A'
link: (scope, $elm, attrs) ->
$elm.on 'click', (e) ->
e.preventDefault()
scope.getFullReview () ->
console.log "Scrolling'
$("body").animate
scrollTop: $elm.offset().top - 100
, "slow"
getFullReview() updates the model after an AJAX call, and then runs the callback.
This works fine in Chrome but not on the iOS simulator - basically a first tap makes the page move (but without triggering the console log - I think this is the URL bar regrowing) and a second is needed to trigger the Directive's link function. I have also installed fastclick as that was mentioned in some posts, but it did not help.
Need ideas :-) (Even some code that would tell me what event is being triggered by safari)
OK, Wow, I do not understand why, but the html above was the last markup on the page, so all of this was happening at the bottom of the screen. When I added some extra margin to the <ul> element, everything started working perfectly!! Bug in Safari?

changePage "jumps" back to old page

I've a big problem with a jQuery Mobile Application:
I'm using custom functions (they are triggered by onClick) to switch the page with currentPage.
It only happens on Android-Devices on sites in which has changed (due to ajax requests) with the integrated browser. iOS and Chrome works nice.
After clicking on an element, the animation started but just before it ends, it switches back to the old page. After a half second, it switches back to the new.
I made a movie of the bug here: http://www.youtube.com/watch?v=sXxvVUxniNg
Thank you very much
Code (CoffeeScript):
class Guide
#categoriesLoaded = false
#loadSearch: ->
$.mobile.changePage $("#guide"),
transition: 'slide'
changeHash: false
if !#categoriesLoaded
#categoriesLoaded = true
GuideApi.getCategories (data) ->
output = Mustache.render $("#tmpl-guide-categories-select").html(),
categories: data
$("#guide-search-category").append output
$("#guide-search-category").val($("#guide-search-category option:first").val());
window.WgSwitchGuide = ->
Guide.loadSearch
I was having the same issue. And I tried everything, I finally end with the solution. What I found was the error was principally within the browser. So I set the configuration of the pushStateEnabled as false. I did it by doing the following, adding this script.
<script type="text/javascript">
$(document).bind("mobileinit", function(){
$.mobile.pushStateEnabled = false;
});
</script>
It should be add before the jquery-mobile script is call, for more information you could see it on JQuery description
And it solved the problem no more jumping back.
I was having the exact same issue on both android and ios. For me, it was happening for heavy pages, i.e., pages with complex elements etc. Looks like you are using "slide" transition, which was what I was using as well. Taking out the page transitions (i.e., $.mobile.changePage("page.html", { transition: "none" })) for those pages resolved this issue for me. Hope this helps.
If you want to retain the transition, you can try preloading the page first when the previous page is being shown, by using the $.mobile.loadPage, and then show the transition. I am myself exploring this route, but it is probably worth trying.
Edit: OK - I explored the last suggestion and this doesn't seem to be working. Will stick with the first option.
Would you try to add the event stopPropagation and preventDefault methods on the first page's click event? This way the default action of the click event will not be triggered. Moreover the stopPropagation prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
event.stopPropagation();
event.preventDefault();
Example:
$("p").click(function(event){
event.stopPropagation();
event.preventDefault();
// change page
});
After trying for weeks to find a solution to this, I ended up doctoring the JQM library to disable page transitions one right after another. It's not a good solution, but it's the only thing I could get to work.
I was getting pages jumping back on both $.mobile.changePage and on anchor links. I used the slide transition, but removing it did not fix the problem. Setting pushStateEnabled to false did not work either. The jumps were happening on all devices and browsers (that I tested, anyway).
So here's what I did to the JQM library (v1.3.2).
Before the $.mobile.changePage function is defined, I added:
var justChangedPage = false;
Then within the function there's a line that goes:
if ( pbcEvent.isDefaultPrevented()) {
return;
}
which I changed to:
if ( pbcEvent.isDefaultPrevented() || justChangedPage) {
return;
}
Then right after this part of the $.mobile.changePage function:
if ( toPage[ 0 ] === $.mobile.firstPage[ 0 ] && !settings.dataUrl ) {
settings.dataUrl = documentUrl.hrefNoHash;
}
I added:
justChangedPage = true;
setTimeout(function() {
justChangedPage = false;
}, 500);
(Putting that earlier in the function didn't work -- all that stuff executes more than once within a single page transition. And half a second seemed to be the minimum timeout that prevented the page jumps.)
I hope this helps someone even if it is a hack...
What is your JQM and Android version?
I'm not sure If I understand correctly. I think transition flicker maybe come from the following assumption.
Heavy page DOM transition.
Using "translate3d" somewhere in css file.
Not using "H/W Acceleration" feature. Enable by add this line to your AndroidManifest.xml in <application>
android:hardwareAccelerated="true"
I encountered exactly the same behaviour and it seems that few people are having the same issue. At first I thought it is caused by jQuery mobile library. Later on, I manage to find where the problem came from and it is a bug in my own code.
I made a demo to explain the issue.
http://jsfiddle.net/pengyanb/6zvpgd4p/10/
Hopefully, this can be hint for people having the same problem.
$(document).on('pagebeforeshow', '#page2', function(){
console.log('Page2 before show');
var htmlGeneratedOnTheFly = '<ul data-role="listview" data-inset="true">';
for(var i=0; i<4; i++)
{
htmlGeneratedOnTheFly += '<li><a>Random html element</a></li><li data-role="list-divider"></li>';
}
htmlGeneratedOnTheFly += '</div>';
$('#page2UiContent').empty();
$('#page2UiContent').append(htmlGeneratedOnTheFly);
$('#page2UiContent').trigger('create');
//////////////////////////////////////////////////
//The following section is where the bug is generated.
//Each on "page2 before show event" will add a OK Button click handler.
//The handlers never get cleared.
//More and more handler is added to the Page2 OK button as pages going back and forth.
//Open the browser's console window to see multiple "Page 2 OK Button clicked!!!" lines on one button click.
//To fix the bug, move the following section out of the $(document).on('pagebeforeshow', '#page2', function(){});
//////////////////////////////////////////////////
$('#page2OkButton').click(function(){
console.log("Page 2 OK Button clicked!!!");
$.mobile.changePage('#page1', {transition:"flip"});
});
//////////////////////////////////////////////
//////////////////////////////////////////////
});
<link href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css" rel="stylesheet"/>
<script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-role="page" id="page1" data-theme="a">
<div data-role="header" data-position="fixed">
<h5>Demo Page 1</h5>
</div>
<div data-role="main" class="ui-content">
<h2>jQuery mobile changepage jumps back to old page demo</h2>
<p>Click "Go To Page 2" button to go to page2</p>
<p>On Page2 click Ok Button to come back to page1</p>
<p>Keeping going back forth between two pages for few times.</p>
<p>Eventually, you will find that clicked on "Go To Page2" button to flip to Page2 but it soon jumps back to page1 automatically. </p>
<h2>Please read the comments in the javascript for explaination</h2>
Go To Page 2
</div>
</div>
<div data-role="page" id="page2" data-theme="a">
<div data-role="header" data-position="fixed">
<h5>Demo Page 2</h5>
</div>
<div id="page2UiContent" data-role="main" class="ui-content">
</div>
<div data-role="footer" data-position="fixed" style="text-align:center;">
<div data-role="navbar">
<ul>
<li><a id="page2OkButton" class="ui-btn ui-icon-check ui-btn-icon-left">OK</a></li>
</ul>
</div>
</div>
</div>

jQuery UI tabs: How do I load a specific element from a different page?

I have jQuery UI tabs set up, but a problem that I'm having with links to different pages is that they load all contents of the page into the tab. This includes the footer, header, and other navbars that I don't want in the tab. What if I would only like to load a single ID from that page?
My tabs are set up this way:
<div id="mytabs">
<ul>
<li>Awesome page</li>
<li>Foo</li>
</ul>
</div>
Nothing much going on in the jQuery...
$(function() {
$( "#mytabs" ).tabs();
});
Let's say this is the html of "awesomepage" (that the first link targets):
<html>
<head>
<title>awesome page</title>
</head>
<body>
<div id="header">bla</div>
<div id="awesomeness">awesomeness!</div>
<div id="footer">fdsfd</div>
</body>
</html>
...And I only want the tab to load #awesomeness from the page. How would I go about doing this? I've read into some guides that do that by adding a data-target="#youridhere" attribute to the HTML, but I'm still confused on how to implement the javascript. It seems like this is a convenient solution, as I won't be targeting the same ID in every page. Any clues on how to get the javascript working?
Thanks in advance!
The function that allow to load partial code of the response is the $.load() function.
Unfortunately, the tabs() feature does not use this function but use $.ajax instead.
You can try this solution:
You can try to stop the default processing on the beforeLoad callback and manage your ajax call with the $.load() method.
(base on the 1.9 documentation, you may should adapt)
$('#tabs').tabs({
// Callback run when selecting a tab
beforeLoad: function(event, ui) {
// If the panel is already populated do nothing
if (ui.panel.children().size() > 0)
return false;
// Make your own ajax load (with fragment feature)
ui.panel.load(ui.tab.attr('href') + ' #yourFragment');
// stop the default process (default ajax call should not be launched)
return false;
});
NOTICE: I'm not sure about extracting the URL with ui.tab.attr('href'), check before what object is ui.tab, but it should be easy to retrieve the href parameter.
Good luck
Got the solution :) Using one of the answers as a reference point, the tabs can now load a single element specified in the data-target attribute. Here is the modified version:
$(function() {
$('#tabs').tabs(
{
beforeLoad: function(event, ui) {
if (ui.panel.children().size() > 0)
return false;
ui.panel.load($('a', ui.tab).attr('href') + $('a', ui.tab).attr('data-target'));
return false;
}
});
});

click event using jquery live

I have the following script which works as long as the are static html
$('li.tab').each(function(index) {
$("#tab" + index ).click(function() {$("#tabs").tabs( "select" , index );});
});
This is what the static html looks like:
<div class="item" id="tab0"><div class="icon" style="background-image: url('http://intranet/icon0.png');"></div> Default</div>
<div class="item" id="tab1"><div class="icon" style="background-image: url('http://intranet/icon1.png');"></div> Reports</div>
<div class="item" id="tab2"><div class="icon" style="background-image: url('http://intranet/icon2.png');"></div> Other</div>
If I use a database to generate the 3 html lines via jquery/ajax, do I have to use the jquery live function to connect the click event look in the script above?
If yes, how would I do this?
yes you need to use live
$('li.tab').each(function(index) {
$("#tab" + index).live('click', function() {
// ...
});
});
$('.your_target_class').live('click', function () {
//your code here.
});
Instead of .live(), use .delegate() which you bind to an object that surrounds what you're targeting. You can chain .delegate() plus it's better performance wise (you can look it up here http://jquerybyexample.blogspot.com/2010/08/bind-vs-live-vs-delegate-function.html)
Also, don't forget to use .die()/.undelegate(), otherwise you're running a risk of firing multiple requests (ie, if your .live() declaration gets called multiple times, your click event will fire multiple times. You can look this up here jQuery UI ajax tabs - requests multiplying when loading links within tabs)
Mind you, jQuery 1.4.2 has a bug in it's .live(), take that into account.

Resources