I have a view that uses an existing div as an element. Div is being used as a horizontal slider with next and pev buttons...
<div id='wrapperHomeScreen'>
<div id='wrapperHomeSlides'>
<div id='slideHomeScreen1' class='slideHomeScreen' >
<div> </div>
</div>
<div id='slideHomeScreen2' class='slideHomeScreen'>
<div> </div>
</div>
</div>
<a href='#tab0' id='btnMainPrev' class='btnScreenDir'></a>
<a href='#tab1' id='btnMainNext' class='btnScreenDir'></a>
</div>
In backbone view I am binding click event to the directions button, and in the event function I am using jquery to animate the slide. Now I need a way to use router with the direction buttons.
here is the view...
var HomeScreenView = Backbone.View.extend({
el:'#wrapperHomeScreen',
initialize: function() {
this.listenTo(Backbone.history, 'route', this.onRouteChanged);
},
events: {
'click .btnScreenDir': 'slide',
'click .btnHomeSlide':'slide',
},
slide: function(e) {
e.preventDefault();
target = $(event.target)
var id = target.attr('id');
var position = $('#wrapperHomeSlides').position();
router.navigate( target.attr('href'), {trigger: true} );// navigate to url
if (id == 'btnMainPrev'){
if(currentSlide != 0 ){
currentSlide -= 1;
}
}else if(id=='btnMainNext'){
if(currentSlide != homeSlidesCount - 1 ){
currentSlide += 1;
}
}
newPos = -1 * currentSlide * slideWidth;
$('#wrapperHomeSlides').animate({left: newPos}, 500);
},
onRouteChanged: function(e) {
//will i use this function?
}
});
And the router:
var Router = Backbone.Router.extend({
routes: {
"tab0": "showTab1",
"tab1": "showTab2"
},
showTab1: function() {
},
showTab2: function() {
}
});
Just try to use router.navigate method:
router.navigate('tab1');
and
router.navigate('tab2');
Related
I'm new to angularJS, and now I'm trying to realize some parts.
The questions is: how do I get access to callback onFinish() which is passed to component "my-timer" and run it? this.onFinish() returns the error.
Here is my markup:
<div ng-app="app" ng-controller="MyCtrl as myCtrl">
<div>
Status: {{myCtrl.status ? myCtrl.status : 'Waiting...'}}
</div>
<div>
<button ng-click="myCtrl.addTimer(5)">Add timer</button>
</div>
<div ng-repeat="timer in myCtrl.timers">
<div>
<h3>Timer {{timer.id}}</h3>
<button ng-click="myCtrl.removeTimer($index)">X</button>
<my-timer id="{{timer.id}}" start-seconds="{{timer.seconds}}" on-finish="myCtrl.onFinish(endTime)"></my-timer>
</div>
</div>
</div>
And here is index.js
var app = angular.module('app', []);
app.controller('MyCtrl', class {
constructor($scope) {
this.status = null;
this.timerId = 0;
this.timers = [];
this.addTimer(10);
this.addTimer(3);
console.log($scope);
}
addTimer(seconds) {
this.timers.push({
id: this.timerId++,
seconds
});
}
removeTimer(index) {
this.timers.splice(index, 1);
}
onFinish(endTime){
this.status = `Timer finished at ${endTime}`;
console.log(endTime);
}
});
app.component('myTimer', {
bindings: {
id: '#',
startSeconds: '#',
onFinish: '&',
},
controller: function($interval, $scope) {
this.endTime = null;
this.$onInit = function() {
this.countDown();
};
this.countDown = function() {
$interval(() => {
this.startSeconds = ((this.startSeconds - 0.1) > 0) ? (this.startSeconds - 0.1).toFixed(2) : 0;
}, 100);
};
},
template: `<span>{{$ctrl.startSeconds}}</span>`,
});
And here is jsFiddle
this.$onInit = function() {
this.countDown();
};
this.onFinish('1');
The problem here is that you tried to execute this.onFinish right in controller's body. And that wont work that way. If you want this function to be called during initialization, move it to $onInit
this.$onInit = function() {
this.countDown();
this.onFinish('1');
};
Otherwise, call it from another component method. You can only declare variables and component methods in controller body, but not call functions.
I want to use ion-refresher for a html page which is having 3 div elements. Each div element will do different functions like allShow(), earnedShow() and redeemShow().
I'm using popover component to filter my data. For example, 'All' will have all data, 'Earned' will display only earned details and 'Redeemed' will display only redeemed details. I've written all the views in a single html itself. What I want is, when I'm in 'Earned' field, and if I'm trying to pull refresh the page means, only the function responsible to that div should appear, it should not go to 'All'
Please suggest a way how to use this
$scope.allShow = function()
{
$scope.All = true;
$scope.Earned = false;
$scope.Redeemed = false;
//some function
}
$scope.earnedShow = function()
{
$scope.All = false;
$scope.Earned = true;
$scope.Redeemed = false;
//some function
}
$scope.redeemShow = function()
{
$scope.All = false;
$scope.Earned = false;
$scope.Redeemed = true;
//some function
}
$scope.doRefresh = function() {
console.log('Refreshing!');
$timeout( function() {
// $scope.allShow();
$scope.allShow();
$scope.$broadcast('scroll.refreshComplete');
}, 500);
};
<ion-content scroll="true" >
<ion-refresher on-refresh="doRefresh()" pulling-text="Pull to refresh...">
</ion-refresher>
<div ng-show="All" >All
</div>
<div ng-show="Earned" >Earned
</div>
<div ng-show="Redeemed" >Redeemed
</div>
</ion-content>
You should refresh depending the current selected div. There are plenty simple solution, but for your logic:
$scope.doRefresh = function() {
console.log('Refreshing!');
$timeout( function() {
if ($scope.All === true) {
$scope.allShow();
}
if ($scope.Earned === true) {
$scope.earnedShow();
}
if ($scope.Redeemed === true) {
$scope. redeemShow();
}
$scope.$broadcast('scroll.refreshComplete');
}, 500);
could be the solution
I am trying to call imagesLoaded function (which is imported properly in the scripts area), but when calling it from inside a component prop, I get an error that it is indefined.
my code:
var MasonryContainer = React.createClass({
imagesLoadedFunc: function() { //omitting the imageloaded call here fix everything
this.imagesloaded();
this.refs[reference].getDOMNode().imagesLoaded(function() {
this.masonry.layout()
});
},
componentDidMount: function() {
if (!isBrowser) return;
this.initializeMasonry();
this.performLayout();
this.imagesLoadedFunc();
},
componentDidUpdate: function() {
if (!isBrowser) return;
this.performLayout();
this.imagesLoadedFunc(this);
},
domChildren: [],
initializeMasonry: function(force) {
if (!this.masonry || force) {
this.masonry = new Masonry(this.refs[reference].getDOMNode(), options);
this.domChildren = this.getNewDomChildren();
}
},
getNewDomChildren: function () {
var node = this.refs[reference].getDOMNode();
var children = options.itemSelector ? node.querySelectorAll(options.itemSelector) : node.children;
return Array.prototype.slice.call(children);
},
diffDomChildren: function() {
var oldChildren = this.domChildren;
var newChildren = this.getNewDomChildren();
var removed = oldChildren.filter(function(oldChild) {
return !~newChildren.indexOf(oldChild);
});
var added = newChildren.filter(function(newChild) {
return !~oldChildren.indexOf(newChild);
});
var moved = [];
if (removed.length === 0) {
moved = oldChildren.filter(function(child, index) {
return index !== newChildren.indexOf(child);
});
}
this.domChildren = newChildren;
return {
old: oldChildren,
'new': newChildren, // fix for ie8
removed: removed,
added: added,
moved: moved
};
},
performLayout: function() {
var diff = this.diffDomChildren();
if (diff.removed.length > 0) {
this.masonry.remove(diff.removed);
this.masonry.reloadItems();
}
if (diff.added.length > 0) {
this.masonry.appended(diff.added);
}
if (diff.moved.length > 0) {
this.masonry.reloadItems();
}
this.masonry.layout();
},
componentWillReceiveProps: function() {
setTimeout(function() {
this.masonry.reloadItems();
this.forceUpdate();
}.bind(this), 0);
},
render: function () {
return (
<div className="content" ref="masonryContainer">
<div className='Item'>
<img src="/img/gallery/3.jpg"></img>
</div>
<div className='Item'>
<img src="/img/gallery/11.jpg"></img>
</div>
<div className='Item'>
<img src="/img/gallery/12.jpg"></img>
</div>
<div className='Item'>
<img src="/img/gallery/12.jpg"></img>
</div>
<img src="/img/gallery/4.jpg"></img>
<img src="/img/gallery/5.jpg"></img>
<img src="/img/gallery/6.jpg"></img>
<img src="/img/gallery/7.jpg"></img>
<img src="/img/gallery/8.jpg"></img>
<img src="/img/gallery/9.jpg"></img>
</div>
);
}
});
React.render(
<MasonryContainer/>, document.getElementById('reactbody')
)
</script>
if I call the imageloaded constructor outside of the react component, it is working.
What am I missing?
Your calling imagesloaded using this,
this.imagesloaded();
However, imagesloaded is not part of your component, nor a standard in React. Thus, this.imagesloaded is undefined, since it never has been declared. Try removing the "this" part of the statement.
imagesLoadedFunc: function() {
imagesloaded();
//the rest of the method
},
I've been through similar discussions and still had no clue why my events are not firing. It seems I lack some fundamental understanding about how backbone events work.
Here is my code:
(function() {
MP.IndicatorView = Backbone.View.extend({
template: JST['backbone/templates/indicator'],
className: 'row indicator',
initialize: function() {
console.log(this);
console.log(this.el);
_.bindAll(this, 'collapse');
},
events: {
"click .control" : "collapse"
},
collapse: function (e) {
console.log('shit');
var $el = $( e.target );
$el.toggleClass( 'expand' );
var $panelToPoke = $el.
parents( '.top-container' ).
siblings( '.bottom-container' )
, $parentPanel = $panelToPoke.parents('.indicator')
, isVisible = $panelToPoke.is( ':visible' );
$parentPanel.toggleClass( 'expanded' );
isVisible ? $panelToPoke.slideUp() : $panelToPoke.slideDown();
},
render: function () {
// Don't show offers that have no transactions
if (this.model.get('transactionCount') > 0) {
this.$el.html( this.template(this.model.for_template()) );
}
return this.$el;
}
});
MP.IndicatorsView = Backbone.View.extend({
el: '#indicators',
render: function () {
var view;
var subViews = this.collection.reduce(function ( memo, indicator ) {
view = new MP.IndicatorView({ model: indicator });
memo += view.render().html();
return memo
}, '');
this.$el.html( subViews );
return this;
}
});
})();
How views are instantiated:
var indicators = new MP.Indicators( coordinator.dump() );
var indicatorsView = new MP.IndicatorsView({ collection: indicators });
indicatorsView.render();
Template:
Views:
<div class="row indicator">
<div class='top-container'>
<ul class="inline-list mainpanel">
<li>
<div class='control expand'></div></li>
<li class="state <%= is_active ? 'active' : 'expired' %>"></li>
Here is a working solution http://jsfiddle.net/hcKv2/
The main problem was that you are used .html() instead of backbone view element .$el inside of your indicatorsView.render() method.
You need to return this inside of render methods to achieve chain pattern, but it is not necessary it is ok if you are returning $el in child view.
render: function () {
var view;
var subViews = this.collection.reduce(function ( memo, indicator ) {
view = new MP.IndicatorView({ model: indicator });
//memo += view.render().html();
this.$el.append( view.render() );
// or this.$el.append( view.render().$el );
// if you return this inside render method
return memo
}, '');
//this.$el.html( subViews );
return this;
}
Have a good coding.
some reference to furthur explain why:
http://ianstormtaylor.com/rendering-views-in-backbonejs-isnt-always-simple/
Insert backbone rendered view in twitter bootstrap popover like below. Problem is that when insert throught content option backbone events for that view don`t fire. I inserted view in div for test with $(selector).html attendanceShow.render().el events work without problem. Thank you in advance
attendance = new Attendance()
attendance.url = "#{attendanceUrl}/#{attendanceId}"
attendance.fetch
success: ->
attendanceShow = new ExamAttendanceShow({model: attendance })
currentTarget.popover
html : true
content: ->
attendanceShow.render().el
Best regards,
Georgi.
From what I understand, based on your code and your description you are only creating an instance of the popover but never showing it. I have a live demo working but not with CoffeeScript (I personally hate CoffeeScript), you can see the code below and at this jsfiddle.
data1.json
{"content": "lorem ipsum dolor sit amet"}
index.html
<div class="container">
<div class="row">
<button class="btn" data-target="popover">Popover</button>
</div>
<div class="row"> </div>
<div class="row">
<button class="btn" data-action="change-content">Change Content</button>
</div>
</div>
main.js
var Main = Backbone.View.extend({
model: null,
item: null,
popover: false,
events: {
'click .btn[data-target]': 'button_click',
'click .btn[data-action="change-content"]': 'change_content'
},
initialize: function() {
_.bindAll(this);
this.model = new PopoverModel();
this.model.view = new PopoverContentView({model: this.model});
this.item = this.$('.btn[data-target]');
this.item.popover({
html: true,
content: this.model.view.render().el
});
},
button_click: function(event) {
if (!this.popover) {
this.model.url = 'js/data1.json';
this.model.fetch({
success: this.model_fetched
});
} else {
this.popover = false;
}
},
model_fetched: function() {
if (!this.popover) {
this.item.popover('show');
} else {
this.item.popover('hide');
}
this.popover = !this.popover;
},
change_content: function(event) {
this.model.set('content', 'Some random content... ' + parseInt(Math.random() * 10));
}
});
var PopoverModel = Backbone.Model.extend({
defaults: {
content: ''
}
});
var PopoverContentView = Backbone.View.extend({
initialize: function() {
_.bindAll(this);
this.listenTo(this.model, 'change', this.render);
},
render: function() {
this.$el.html(_.template('<%= content %>', this.model.toJSON()));
return this;
}
});
var main = new Main({
el: '.container'
});
I have a similar issue, to expand on Georgi's answer, please try this:
Place a button or a link in your popup (instead of the dynamic text you place) and handle an event, say click event on it.