Backbone.js Click Event Won't Fire - backbone.js

I have been trying to learn backbone.js, but I can't figure out why my click event isn't firing when I click the home link. I'm fairly new to backbone and I'm just not sure what am I missing? I've looked up a bunch of different tutorials on the net, but can't seem to find the lose hole. Please help!
Backbone.js
var HomeView = Backbone.View.extend({
el: $('.content'),
events:{
"click #home": "animateNavigation"
},
initialize: function(){
_.bindAll(this, 'displayTrips');
// Add the model collections
this.collection = new ModelList();
this.collection.bind('add', this.displayTrips); // Collection event binder
},
animateNavigation: function(){
alert('test');
return false;
},
displayTrips: function(params){
var items = params.get('data');
}
});
var home_view = new HomeView();
HTML
<div class="content">
<div class="left">
<ul>
<li>
<div class="nav_arrow"></div>
<a href="home" class="active" id="home">
<img alt="Home" src="/assets/img/nav/left/star.png">
<span>Home</span>
</a>
</li>
<li>
<a href="tropical" id="tropical">
<img alt="Tropical" src="/assets/img/nav/left/fins_grey.png">
<span>Tropical</span>
</a>
</li>
</ul>
</div>
</div>

You're finding the element at the time the model is declared. If you have your script in the header or anywhere before this content, that element doesn't exist yet. I don't know that there should be any good reason to use $('.content') here anyway, just use '.content'
Edit: Well, I see you are also declaring a new instance of your view as well. I don't know if that line represents literally what you have in your script, or you just put it there for the purpose of demonstrating your basic use. I generally define the views and models elsewhere from the page logic (which would have the instances of those things), primarily so that I can reuse them.

Could you add
console.log(home_view.$el.html());
at the end, to check the Dom Element of home_view please. I assume that something goes wrong when binding the view to the Dom element.

I found this solved it for me:
var home_view = new HomeView({el:$('.content')});
UPDATE - better than that, do this:
var home_view = new HomeView({el:'.content'});
then this.$el will work as the above post says

Related

Removing items from an array with Angular

Yes, it has been asked before, and I've read all the answers but nothing seems to work. So I'm asking for an extra pair of eyes to see if you can find any singularity in my code that is making it not work as it should. (I tried this code and logic somewhere else and it seems to work fine). No errors in the console by the way
I am simply trying to remove an item from the view when someone clicks the x on the picture.
Here is the controller
app.controller('galleryController', ['$scope', '$http', function($scope, $http) {
$http.get('data/galleries.json').success(function(data){
$scope.galleries = data;
}).error(function(error) {
console.log(error);
});
$scope.removeGalleryItem=function(gallery){
var removedGallery = $scope.galleries.indexOf(gallery);
$scope.galleries.splice(removedGallery, 1);
};
}]);
and my view
<div class="col-xs-12 col-md-3" ng-repeat="gallery in galleries" >
<a class="gallery-item" ng-href="{{gallery.img}}" ng-class="{true:'active',false:''}[checked]"
title="Nature Image 1" >
<div class="image">
<img ng-src="{{gallery.img}}" alt="Nature Image 1"/>
</div>
<div class="meta">
<strong>{{gallery.title}}</strong>
<span>{{gallery.desc}}</span>
</div>
</a>
<ul class="gallery-item-controls">
<li><label class="check"><input type="checkbox" class="icheckbox" ng-model="checked" /></label></li>
<li><span class="gallery-item-remove"><i class="fa fa-times" ng-click="removeGalleryItem(gallery)"></i></span></li>
</ul>
</div>
Angular 1.5.8
Thanks
You can pass an $index in your click function like this.
<i class="fa fa-times" ng-click="removeGalleryItem(galleryItem, $event , $index)">
and use $scope.galleries.splice(index, 1); inside your click function removeGalleryItem, make sure you have index parameter too like this.
$scope.removeGalleryItem = function(gallery , event, index){
$scope.galleries.splice(index, 1);
};
Hope this helps..
After doing some research I think the problem is that galleryController is defined somewhere in your markup but the elements in the gallery are not inside of where that controller is defined.
Referring to http://joli.sitedev.online/#/gallery. In file slidesController.js where galleryController is defined I put a break here and the code pauses:
I also put a break point here but the code does not pause when clicking on a delete button:
Looking at the markup I can't see any sign of ng-controller="galleryController" so I can't see how galleries in the ng-repeat is populated:
Maybe it is through this:
If it is through that then it would explain things as that directive has its own controller. Any further information would help and I'm sure we can clear this up.
If I understood correctly your question, if you want to delete a particular element both from DOM and Array containing these particular elements you can do the following:
<!-- Intercept that particular Element with $event-->
<i class="fa fa-times" ng-click="removeGalleryItem(galleryItem, $event)">
Lets supposing you are repeating some galleryItems and they have a name property.
And on your controller:
$scope.removeGalleryItem(galleryItem, $event){
//Save galleryItem Name
var itemName = $($event.currentTarget).name(); // if it has it on html
var itemName = galleryItem.name; // if it has a property
//Get the target and remove it
$($event.currentTarget).remove();
//Using lodash, loop through your array and remove that exact object from it.
//Ofc you can do a normal loop through it.
$scope.galleries = _.remove($scope.galleries, function(n) {
return n != itemName;
});
//Then, if the change does not happen in your DOM
$scope.$apply();
}
Hope I've been helpful.
I have made some changes to fix this issue and you can check it at this link.
The problem here was that there was a typo in the html snippet that was calling the removeGalleryItem(galleryItem, $event). The parameter name should have been gallery, not galleryItem, since there is no such object by the name galleryItem, hence inside this method, the parameter value was undefined. Once I fixed it, I was able to get the gallery object within the removeGalleryItem method and the following code worked absolutely fine:
$scope.removeGalleryItem=function(gallery){
var selectedGallery = $scope.galleries.indexOf(gallery);
$scope.galleries.splice(selectedGallery, 1);
};
Also note that, I have removed the $event attribute from the method declaration and from the html method call as we didn't need it in the above mentioned approach.
<i class="fa fa-times" ng-click="removeGalleryItem(gallery)"></i>

List items not dragging using Sortable.js

Sortable.Js newbie here, so please be gentle.
I'm trying to implement a sortable list in my page using Sortable.js. I'm not getting any errors upon execution, however when I tried to drag my list items, they're not moving at all.
Here's my HTML:
<ul id="forcedranking" class="wizard-contents-container-ul forcedRankCls" ng-show="isForcedRankingQuestion">
<div class="answers-container">
<div class="answer-child-container">
<li ng-repeat="query in currentQuestionObject.choices | orderBy:['sequence','answer']" class="listModulePopup forcedRankingChoice" data-index="{{$index}}" ng-model="query.value">
{{query.answer}}
</li>
</div>
</div>
</ul>
And here's my JS:
/* Get current input type for Clear All checkbox activation */
$scope.currentInputType = $scope.currentQuestionObject.inputType.toLowerCase();
if ($scope.currentInputType == "forced ranking") {
$scope.isForcedRankingQuestion = true;
/* SORTABLE FOR FORCED RANKING */
var mySort = document.getElementById("forcedranking");
// forcedranking is my id for the <ul>
var sortable = Sortable.create(forcedranking, {});
// Tried setting this because I thought this was the culprit. Turns out it's not.
sortable.option("disabled", false);
I called my Sortable.js like so (underneath my angularJS libraries):
<script type="text/javascript" src="content1/carousel/Sortable.js"></script>
Overall, I think Sortable's a really neat library, which is why I want to make it work so bad. But I just don't know what I'm doing wrong here.
The problem is you are not following the sortable angular documentation. They recently change the project and separated the js from the frameworks.
So first you need to include the lib and the angular sortable lib angular-legacy-sortablejs
Sortable.js
ng-sortable.js
Second inject the module 'ng-sortable' in your app
Then you can pass the options (if you need to) in the html via directive or use it in the controller
HTML:
<ul ng-sortable="{group: 'foobar'}">
<li ng-repeat="query in currentQuestionObject.choices">{{query.answer}}</li>
</ul>
Or you can pass an object declared in your controller with the options, ex:
$scope.sortableConfig = {
group: 'collection',
animation: 150,
handle: '.handle',
filter: '.inbox'
}
<ul ng-sortable="sortableConfig">
<li ng-repeat="collection in test">
<div class="handle"></div>
{{collection.name}}
</li>
</ul>
Hope this help you!
I think what's going on here is that your JS is being executed before Angular is done rendering all the LI items, but it's hard to tell from your snippet of JS.
Just for testing, see if the items become draggable after 1 second if you change these two lines:
/* SORTABLE FOR FORCED RANKING */
var mySort = document.getElementById("forcedranking");
// forcedranking is my id for the <ul>
var sortable = Sortable.create(forcedranking, {});
into this:
window.setTimeout(function() {
/* SORTABLE FOR FORCED RANKING */
var mySort = document.getElementById("forcedranking");
// forcedranking is my id for the <ul>
var sortable = Sortable.create(forcedranking, {});
}, 1000);
Also, I don't believe that <div> elements are valid children for <ul> elements, so that may also be your problem. If the Javascript change does nothing, then perhaps you should try to change your html so that your <li> items are direct children of the <ul> element.
Hope this helps.

Angular JS ng-repeat and the 'this'

i'm new in AngularJS, but did some jQuery before. i've got a problem to understand how to get the clicked element / it's parent to make some changes like change the text, an icon or a class in the item where i made the click.
the simple HTML:
<ul ng-controller="basketCtrl">
<li ng-repeat="item in item">
<button ng-click="addToBasket(Itemid,this,whatever)">
<i class="myBasketicon">
<span>Buy now</span>
</button>
</li>
</ul>
what i want to do:
$scope.addTobasket = function (id, elem, whatever){
// to some JSON-Server-stuff - that works perfect
// now my problems, :
//change this -> myBasketIcon -> myOKicon
//change this -> span text Buy now-> Thanks for buying
// give the this -> li an class => 'changed'
}
I really tried a lot, f.e with ng-model in the tags, arrays... search the web half the day... but didn't find anything that matches my problem.
Maybe it's just the way of thinking not the angular way... so please help :O)
Kind regard from Hamburg, Germany
Timo
You should be able to do this by changing a property (angular way), no need to access the element in the ng-click handler,and using ng-class and angular binding on that property.
<ul ng-controller="basketCtrl">
<li ng-repeat="item in items" ng-class="{'changed': item.added}">
<button ng-click="addToBasket(item)">
<i ng-class="{'myBasketicon':!item.added,'myOKicon':item.added }">
<span>{{item.added ? "Thanks for buying" : "Buy now"}}</span>
</button>
</li>
</ul>
and in your handler just do:
$scope.addTobasket = function (item){
item.added = true;
}
Most cases, whole purpose of using angular is to avoid DOM manipulation and let angular manage it, you just deal with the models/viewmodels and bindings.
You should add methods for the icon class and text that change their results based on the state of the object, or use custom a custom directive. You definitely don't want to be doing any DOM manipulation (changing text/classes etc) the way you would have done with jQuery.
For the method-based approach, something like this for your markup:
<li ng-repeat="item in item">
<button ng-click="addToBasket(item)">
<i ng-class="getClass(item)">
<span>{{getMessage(item)}}</span>
</button>
</li>
and on your controller:
.controller('ShoppingListCtrl', function($scope) {
$scope.getClass = function(item) {
return item.inBasket ? 'myOkIcon' : 'myBasketIcon';
};
$scope.getMessage = function(item) {
return item.inBasket ? 'Thanks for buying' : 'Buy now';
};
})
This could also be done with a custom directive which is a super powerful way to do things (and definitely worth figuring out) but may be overkill for just starting out. If you find you are adding a lot if methods for doing these sorts of things go with directives.

Backbone.Marionette Layout + Region + View inserts an extra element, breaking Bootstrap styles

I'm running into a problem getting Backbone.Marionette to cooperate with Twitter Bootstrap. Bootstrap expects markup to conform to predefined patterns in order to work, but the way that Backbone and Marionette handle things, it seems to be impossible to use a Marionette.Layout to generate Bootstrap-compliant markup for a navbar with an embedded dropdown.
Here's the problem:
Let's say I have a Marionette.Layout representing the navbar, and I want to have a region, where I will put the CollectionView or CompositeView that manages the items in the dropdown. The region is a selector, so in this case if we have:
<div class="navbar">
<ul class="nav">
<li>Static item</li>
<li id="dynamic-dropdown"></li>
</ul>
</div>
Then the Layout would specify the region for the dynamic dropdown as follows:
Marionette.Layout.extend({
regions: {
dropdown: '#dynamic-dropdown'
}
...
});
I would then have a CompositeView that takes care of rendering the dropdown item models, specifies the extra markup for the Bootstrap dropdown, and so forth. The problem is that it appears to be impossible to make #dynamic-dropdown be the $el for the CompositeView, as Backbone always inserts an extra div (or whatever you specify in tagName). In order for the dropdown to appear as expected, I need to get rid of that extra element and have the view's root be #dynamic-dropdown.
I've put together a jsfiddle illustrating what I mean.
tl;dr How do I make a View's root element be the region specified in a Marionette.Layout?
You just need to make sure that the markup that is generated in the end follows the same as required by Bootstrap (use the console to debug).
The required markup is as follows:
The markup generated by your code has the following problems:
So, to fix it you have to change your nav template to:
<script type="text/html" id="nav">
<div class="navbar">
<ul class="nav" id="dropdown">
</ul>
</div>
</script>
And your views to render <li> instead of <div>
var DropdownItem = Marionette.ItemView.extend({
tagName: 'li',
template: "#dropdown-item"
});
var DropdownView = Marionette.CompositeView.extend({
template: "#dropdown-collection",
className: 'dropdown',
tagName: 'li',
itemView: DropdownItem,
itemViewContainer: '#dropdown-items'
});
Here is the working version: http://jsfiddle.net/7auhR/6/

Backbone.js - How to use 'ul' 'li' tags as tab widget using MVC?

The question may confuse you, I want to achieve the 'tab' widget from 'ul' and 'li' tags using 'Backbone.js' and it's MVC concept. How to do?
For example
<ul>
<li> One </li>
<li> Two </li>
<li> Three </li>
</ul>
When the link 'one' is clicked then I want to show some content (div) and want to hide others how to do using MVC concept ?
This could be done without Backbone and MVC, but I want to do this with Backbone, please help me.
You can create a Backbone.View that will handle all of your "tabs". This Backbone.View should cover the or whatever is above your content.
Based on your ul, you can add CSS selectors or other attributes:
<div id="mainDiv">
<ul>
<li class="tab-one">One</li>
<li class="tab-two">Two</li>
<li class="tab-three">Threeli>
</ul>
<div id="tab1" class="tab">...</div>
<div id="tab2" class="tab">...</div>
<div id="tab3" class="tab">...</div>
</div>
Create a Backbone.View to handle the page events:
MyView = Backbone.View.extend({
el: $('#mainDiv'),
events: {
'click .tab-one': 'showTabOne',
'click .tab-two': 'showTabTwo',
'click .tab-three': 'showTabThree'
},
showTabOne: function() {
$(this.el).find('.tab').hide();
$(this.el).find('#tab1').show();
},
showTabTwo: function() {
$(this.el).find('.tab').hide();
$(this.el).find('#tab2').show();
},
showTabThree: function() {
$(this.el).find('.tab').hide();
$(this.el).find('#tab3').show();
}
...
}
This is just to show and hide tabs using Backbone. You can do a lot more with Backbone :)
Edit: If you're tab list is dynamic, you can put the initialization of events using jquery way inside the Backbone.View's initialize() function. This will get invoked once you instantiate a Backbone.View (var view = new MyView;)

Resources