backbone filtering a collection - javascript

I am trying to filter a collection based on an attribute called status. Once filtered I want to re-render the view to reflect the filtered results. So far I have come up with this function in my collection.
var ProjectCollection = Backbone.Collection.extend({
url: '/projects',
model: app.Project,
status: function( status ) {
return this.filter(function(project){
return project.get('status') == status;
});
},
});
In my view I the run the following,
filterStatus: function(e) {
e.preventDefault();
var elm = $(e.currentTarget),
status = elm.data('statusid');
this.collection.reset( this.collection.status( status ) );
}
The render function is below along with it's functions that also get called,
render: function() {
this.$el.empty();
console.log("ProjectDashboardView render");
if(this.collection.length < 1) {
var noProjects = new app.noProjectsDashboard;
} else {
this.addAll();
}
$(".month-column").height($(".project-holder").height() + 50);
},
addAll: function() {
console.log("allAdd");
this.collection.each(function(model){
this.addOne(model)
}, this);
},
addOne: function(model) {
var view = new app.ProjectTimelineEntry({
model: model
});
this.$el.append( view.render() );
var number_of_days_in_calendar = 0;
$('.month-column').each(function(){
number_of_days_in_calendar = number_of_days_in_calendar + parseInt($(this).data('days'));
});
var day_width = 1/(number_of_days_in_calendar) * 100;
//Is the start after the end of Feb?
var start_date = new Date(model.get('start_date'));
var march_date = new Date("03/01/2014");
var current_month = start_date.getMonth() + 1;
var march_month = march_date.getMonth() + 1;
console.log(current_month, march_month);
if(current_month <= march_month) {
var start_date_offset = model.get('num_days_from_year_start') * day_width;
var duration_of_project = model.get('run_number_days') * day_width;
//view.$('.duration-bar').css("background-color", model.get('color'));
view.$el.find('.duration-bar').css({
width : duration_of_project + "%",
"margin-left" : start_date_offset + "%"
}, 500);
} else {
var start_date_offset = (model.get('num_days_from_year_start') + 2) * day_width;
var duration_of_project = model.get('run_number_days') * day_width;
//view.$('.duration-bar').css("background-color", model.get('color'));
view.$el.find('.duration-bar').css({
width : duration_of_project + "%",
"margin-left" : start_date_offset + "%"
}, 500);
}
// if(Date.parse(start_date) < new Date("01/03")) {
// console.log("before march");
// }
},
Now this filters the collection, however what happens is that when I try and filter the collection again, it filters the collection that I have just reset too, how can I filter the collection, run the views render() function once a filter is complete, but not keep resetting the collection?

As hindmost mentionned, you should add a visible field to app.Project model.
Then in ProjectView attach a listener to this field:
this.listenTo(this.model, "change:visible", this.onVisibleChange)
and the method definition:
onVisibleChange: function(){
$(this.el).css('display', (this.get('visible')) ? 'block': 'none')
}
In your filter method you run over the collection and change the visible field of each model accordingly to if it should or should not being rendered.
var ProjectCollection = Backbone.Collection.extend({
url: '/projects',
model: app.Project,
status: function( status ) {
return this.each(function(project){
project.set('visible', project.get('status') == status)
});
},
});

You have to add extra attribute to collection's model (app.Project) which will store the flag indicating if a project has to be displayed or not.
var app.Project = Backbone.Model.extend({
defaults: {
...
status: '',
display: true
}
};
Then you have to add the code to model View's render which will show/hide View's element depending on value of display attribute:
var ProjectView = Backbone.View.extend({
...
render: function() {
...
if (this.model.get('display'))
this.$el.show();
else
this.$el.hide();
...
return this;
},
...
};
And, finally you have to modify ProjectCollection's status method to set display attribute on each model:
var ProjectCollection = Backbone.Collection.extend({
url: '/projects',
model: app.Project,
status: function( status ) {
this.each(function(project){
project.set('display', project.get('status') == status);
});
},
...
});

Related

How to have multiple list react to each other un Vue.js

Okay so I have three lists defined as Vue.js components that need to react to each other. Site, profile and Employee. This basically means that when I select a site, I want to load the profiles and the employees of this specific site, so on and so forth. The thing is that I can't figure out how to achieve this. Codewise, here's what I have:
selectw.vue
<template lang="pug">
div
.btn.dropdown-toggle.text-left.btn-block.k-selectbox-toggle(tabindex="0", v-on:keydown.down.stop="selectDown", v-on:keydown.up.stop="selectUp", v-on:keydown.enter="updateClose")
k-icon(:icon="currentOption.icon||icon||placeholderIcon", v-if="currentOption.icon||icon||(!currentOption.text&&placeholderIcon)")
span(v-if="currentOption.icon||icon||(!currentOption.text&&placeholderIcon)")
span(v-html="currentOption.html||currentOption.text||placeholder")
.dropdown-menu.pre-scrollable(v-if="searchResults.length")
.search-indicator(hidden v-if="options.length>5")
.dropdown-header.pr-3.pl-3(v-show="options.length>5")
input.form-control(type="text", :placeholder='__("Search...")', style="width:100%", v-model="searchText", v-on:keydown.down.stop="selectDown", v-on:keydown.up.stop="selectUp", v-on:keydown.enter.stop="updateClose()")
//{{__("Search...")}} FIXME because poedit is retarded
a(v-for="(option,index) in searchResults", :class="'dropdown-item '+(option.id==value?'active':'')", href="#" , v-on:mousedown="update(option.id)")
k-icon(:icon="option.icon||icon", v-if="option.icon||icon")
span(v-if="option.icon||icon")
span(v-html="option.html||option.text")
.dropdown-menu.pre-scrollable(v-else)
.dropdown-item {{__("Empty List")}}
input(type="hidden", :name="name", :value="value")
</template>
<script>
var allowClose = true;
// autofocus search in selectbox dropdowns
$(document).on('shown.bs.dropdown', function(e){
var searchInput = $(e.target).find('.search-indicator')
if(searchInput.length){
allowClose = false;
$(e.target).find('.form-control').focus();
}
});
// close on blur
$(document).on('blur', '.k-selectbox-toggle', function(e){
var element = $(this);
if(allowClose){
setTimeout(a=>{
element.next().removeClass("show") // WHY DOES THIS WORK ?!?!?!?
}, 100)
}
allowClose = true;
});
$(document).on('blur', '.k-selectbox-toggle+.dropdown-menu input.form-control', function(e){
var element = $(this);
setTimeout(a=>{
element.parent().parent().removeClass("show") // WHY DOES THIS WORK ?!?!?!?
}, 100);
});
$(document).on('focus','.k-selectbox-toggle', e => {
$(e.target).dropdown('toggle');
})
// mod negative numbers
var mod = (x, n) => ((x%n)+n)%n;
export default {
methods:{
update(id){
if(id!==undefined){
this.$emit('update:value', id)
}
},
updateClose(e){
if(this.searchResults[0]&&_.findIndex(this.searchResults, {id:this.value})==-1) this.$emit('update:value', this.searchResults[0].id);
this.$emit('update:value', this.value);
$(this.$el).find("input.form-control").blur();
$(this.$el).find(".k-selectbox-toggle").blur();
},
selectDown(e){
var index = _.findIndex(this.searchResults, {id:this.value});
if(index==-1)index=-1;
var length = this.searchResults.length;
this.value = this.searchResults[(index+1)%length].id;
e.preventDefault();
},
selectUp(e){
var index = _.findIndex(this.searchResults, {id:this.value});
if(index==-1)index=1;
var length = this.searchResults.length;
this.value = this.searchResults[mod(index-1, length)].id;
e.preventDefault();
}
},
computed:{
searchResults(){
var exclude = this.exclude||[];
if(exclude[0]&&exclude[0].id){
exclude = exclude.map(a=>a.id)
}
return this.options.filter(a=>{
return _.lowerCase(a.text)
.indexOf(
_.lowerCase(this.searchText)
) !== -1;
}).filter(a=>exclude.indexOf(a.id) == -1);
},
currentOption(){
return _.find(this.options, {id:this.value}) || _.find(this.options, {id:-1}) || (this.placeholder?{}:this.options[0]) || {}
}
},
watch:{
options(){
$(this.$el).find(".dropdown-menu").removeClass("show")
}
}
};
</script>
components.js
var modelOptions = {
sites: app.metadata.sites.map(a=>({id:a.id,text:a.name})),
profiles: app.metadata.profiles.map(a=>(
{
id: a.id,
text: a.name,
//FIXME add color tags to k-icon
html: "<span class='color-tag-group'><span data-color="+a.color+" class='color-tag'></span></span> "+a.name
}
)
),
employees: app.metadata.employees.map(a=>{
var colors = a.profiles.map(a=>"<span data-color="+a.color+" class='color-tag'></span>").join("")
return {
id: a.id,
text: a.firstname + " " + a.lastname,
html: "<span class='color-tag-group'>"+colors+"</span> "+a.firstname+" "+a.lastname
}
}),
weeks:weekList
};
var selectBoxSettings = require("./selectw.vue");
Vue.component('k-combobox', _.assign({}, selectBoxSettings, {
props:["model", "value", "placeholder", "strict", "name", "exclude", "context"],
data(){
var context = this.context || "filter";
// filter
// selection
var options = _.clone(modelOptions[this.model]);
// var options = null;
console.log('dsfsdfdsfdsfsd');
console.log(options);
var placeholderIcon = "";
if(this.model=="profiles"){
placeholderIcon = "profile"
}
if (!this.strict){
if(context=="filter"){
options.unshift({
id: -1,
text: app.utils.translate( "All " + _.capitalize(this.model) ),
icon: {profiles: "profile", employees:"user"}[this.model]
});
}
if(context=="selection"){
options.unshift({
id: null,
text: app.utils.translate( "No " + _.capitalize(this.model).slice(0, -1) ),
icon: {profiles: "profile", employees:"user"}[this.model]
});
}
}else{
if(!this.placeholder){
this.$emit('update:value', this.value||options[0].id);
}
}
var icon = "";
if(this.model=="sites"){
icon = "site"
}
return {
options,
searchText: "",
placeholderIcon,
icon
};
},
methods:{
myTesting(e){console.log("my god")}
}
}));
main.vue
<template lang="pug">
div
.btn-group.mb-3
k-combobox.btn-group(model="sites", :value.sync="currentSite")
k-combobox.btn-group(model="profiles", :value.sync="currentProfile")
k-combobox.btn-group(model="employees", :value.sync="currentEmployee")
#print-calendar.btn.btn-primary.d-print-none(onclick="window.print()")
k-icon(icon="print")
|{{__('Print')}}
.btn.mb-3
| {{__("Total:")}}
k-duration.d-inline-block(:minutes="totalMinutes")
br
div(v-if="!isDay(currentWeek)&&currentSite!=-1")
.btn-group.mb-3.mr-3
.btn.btn-primary(v-on:click="copyWeek", v-if="!isDay(currentWeek)") {{__("Copy Selected Week")}}
.btn.btn-primary(v-on:click="copyWeek", v-else) {{__("Copy Selected Day")}}
.btn-group(v-if="sourceWeek")
.btn-group.mb-3(tabindex="0", v-if="weekFuture(currentWeek)&&currentWeek!==sourceWeek")
.btn.btn-primary(v-on:click="pasteWeek") {{__("Paste")}} {{weekFormat(sourceWeek)}} {{__("Here")}}
a.btn-group.mb-3(tabindex="0", v-else, style="cursor: not-allowed", data-toggle="popover", :data-content="__('error_week_copy')")
.btn.btn-primary.disabled {{__("Paste")}} {{weekFormat(sourceWeek)}} {{__("Here")}}
//{{__("error_week_copy")}}
.modal(v-if="popupShown", style="display:block", v-on:click="hideModalSafe")
.modal-dialog.modal-lg(v-on:keydown.enter="syncSchedule()")
.modal-content
h3.modal-header {{moment(currentSchedule.start).format('YYYY-MM-DD')}}
button.close(type="button",v-on:click="popupShown=false") ×
.modal-body
.row
.col.form-group
label(for="schedule-start") {{__('Start')}}
k-input-time(:date.sync="currentSchedule.start")
.col.form-group
label(for="schedule-end") {{__('End')}}
k-input-time(:date.sync="currentSchedule.end")
.col.form-group
label(for="schedule-pause") {{__('Pause')}}
k-input-minutes(:minutes.sync="currentSchedule.pause")
.row
.col.form-group
label(for="schedule-site-id") {{__('Site')}}
k-combobox(model="sites", :value.sync="currentSchedule.site_id", strict="true", "v-on:update:value"="siteUpdateValue")
.col.form-group
label(for="schedule-profile-id") {{__('Profile')}}
k-combobox(model="profiles", :value.sync="currentSchedule.profile_id", context="selection", "v-on:update:value"="profileUpdateValue")
.col.form-group
label(for="schedule-employee-id") {{__('Employee')}}
k-combobox(model="employees", :value.sync="currentSchedule.employee_id", context="selection", "v-on:update:value"="employeeUpdateValue")
.modal-footer
.btn.btn-danger.mr-auto(v-on:click="deleteSchedule()")
k-icon(icon="delete")
| {{__('Remove')}}
.btn.btn-primary(v-on:click="syncSchedule()", tabindex="0") {{__('Save')}}
</template>
<script>
var $fullCalendar = {};
export default {
el: "#vueapp",
data: app.models.manageSchedules,
methods:{
syncSchedule(){
$fullCalendar.storeEvent(_.clone(this.currentSchedule));
this.popupShown = false;
},
deleteSchedule(){
var data={
id: this.currentSchedule.id
};
app.ajax.defaultRequest("delete", "/api/fullcalendar/"+data.id, {}, function(response){
$fullCalendar.removeEvents(data.id);
$fullCalendar.updateTotalDisplayedTime();
app.logger.debug("remove event", response);
});
this.popupShown = false;
},
hideModalSafe(e){
var $ = window.$;
if($(e.target).hasClass("modal")){
this.popupShown = false;
}
},
pasteWeek(){
var data = _.pick(this, [
"sourceWeek",
"currentSite",
"currentProfile",
"currentEmployee"
]);
data.destinationWeek = this.currentWeek;
app.ajax.calendar.copy(data, response=>{
if(response.success){
$fullCalendar.refetchEvents();
}else{
app.models.manageSchedules.layout.ajaxMessage = response.message;
}
});
},
copyWeek(){
this.sourceWeek = this.currentWeek
},
siteUpdateValue(value)
{
var self = this;
// this.loadContent();
app.ajax.defaultRequest("post", "/api/profiles", {"site_id": value}, function(response){
// console.log(response);
// console.log(app.models.manageSchedules);
self.$emit('testing', 'blbblbblb');
//app.metadata.profiles = response.data;
// app.models.manageProfileIndex.profiles = response.data;
});
},
profileUpdateValue(value)
{
},
employeeUpdateValue(value)
{
},
weekFormat(week){
var __ = app.utils.translate;
var [start, end] = week.replace(/\s/g, "").split("#").map(a=>moment(a));
var humanStart = start.format(__("MMM D"));
var humanEnd = end.format(__("MMM D"));
if(humanStart!==humanEnd){
return __("W") + start.week() //+ " - " + humanStart + " " + __("date_to") + " " + humanEnd;
}else{
return humanStart;
}
},
weekFuture(week){
var timestamp = moment(week.replace(/\s/g, "").split("#")[0]).unix()
return timestamp > moment().add(app.metadata.server_offset, 'milliseconds').unix()
},
isDay(week){
var [start, end] = week.replace(/\s/g, "").split("#");
return start === end;
}
},
watch:{
currentSite(){
$fullCalendar.refetchEvents();
this.sourceWeek = "";
},
currentProfile(){
$fullCalendar.refetchEvents();
},
currentEmployee(){
$fullCalendar.refetchEvents();
}
},
beforeCreate(){
var model = app.models.manageSchedules;
_.assign(model,{
popupShown:false,
currentSchedule:{
id: 0,
title: "",
start: "",
end: "",
pause: "",
site_id: 0,
profile_id: -1,
employee_id: -1
},
currentSite: -1,
currentProfile: -1,
currentEmployee: -1,
sourceWeek: "",
currentWeek: "",
hasCalendar: true,
totalMinutes: 0
});
var calendarConfigs = require('../fullcalendarConfigs');
calendarConfigs = _.assign({},calendarConfigs,require('./configs'));
calendarConfigs.eventDrop = function (event, delta, revertFunc){
if(moment(event.start).unix() < moment().add(app.metadata.server_offset,'milliseconds').unix()){
revertFunc();
return;
}
$fullCalendar.storeEvent(event);
}
var $calendar = $('<div class="card mb-3" id="calendar" style="cursor:copy"></div>');
$calendar.insertAfter($('#vueapp'));
$calendar.fullCalendar(calendarConfigs);
$fullCalendar = $calendar.data('fullCalendar');
$fullCalendar.addEvent = function (event) {
if(moment(event.start).unix() < moment().add(app.metadata.server_offset,'milliseconds').unix()){
return;
}
app.logger.debug('addEvent', event);
event.site_id = model.currentSite || app.metadata.sites[0].id;
event.profile_id = model.currentProfile!=-1 ? model.currentProfile || null : null;
event.employee_id = model.currentEmployee!=-1 ? model.currentEmployee || null : null;
this.storeEvent(event);
};
//---------------------------------------------------------
$fullCalendar.storeEvent = function (event) {
var fullcalendarScope = this;
app.logger.debug('fullCalendar - storeEvent', event);
var data = _.pick(event, ["id", "title", "start", "end", "pause", "site_id", "profile_id", "employee_id"])
if(data.start.local){data.start = data.start.local().format();}
if(data.end.local){data.end = data.end.local().format();}
data.type = "calendar";
app.logger.debug('storingData', data);
app.ajax.calendar.store(data, function (response) {
app.logger.debug('storeEvent', response);
var newEvent = _.pick(response, ["id", "className", "start", "end", "pause", "site_id", "profile_id", "employee_id", "title"]);
// app.models[app.metadata.route].totalMinutes = 120;
fullcalendarScope.removeEvents([event.id]);
fullcalendarScope.renderEvent(newEvent, false);
fullcalendarScope.updateTotalDisplayedTime();
});
};
//---------------------------------------------------------
$fullCalendar.editEvent = function (event) {
if(moment(event.start).unix() < moment().add(app.metadata.server_offset,'milliseconds').unix()){
return;
}
app.models.manageSchedules.currentSchedule = _.clone(event);
app.models.manageSchedules.popupShown = true;
};
$fullCalendar.updateTotalDisplayedTime = function () {
var self = this;
var displayedEvents = this.clientEvents(function(event){
if(event.start >= self.view.start && event.start <= self.view.end)
return true;
else
return false;
});
app.models[app.metadata.route].totalMinutes = _.sumBy(displayedEvents, a=>moment(a.end).diff(moment(a.start), 'minutes'));
};
var calendarSources = require('../calendarSources');
$fullCalendar.addEventSource(calendarSources.schedules);
$fullCalendar.addEventSource(calendarSources.holidays);
}
};
</script>
Okay, so as you can see, I have tree files. Selectw.vue is a component that actually defines the basic format of my listboxes. Then, you have component.js which defines the k-combobox component. This specific component is where the lists are actually populated. Right now, they're filled when the page is actually loaded. This component is also what's ultimately used on the main page (main.vue).
The lists emit an event (update:value) when their value changes and I've been able to catch it on the main page and subsequently call a script that retrieves the values I need in the database (see siteUpdateValue function). The thing is that from there, I can't access the list's content. Where I could access the list's content would be in the k-combobox definition, but at this specific place, I can't bind any form of event because there's no template.
So basically, I'm going around in circles right now and I need help figuring out the correct way to do this.
Thanks in advance.

BackBone: get sub view from jquery element

I render a list Post to template after select it from window scroll event and i need to get model and event in this Post.
I want to get view Post for using model or event from route when window scroll event? have a way to do it?
sub view:
Post = Backbone.View.extend({
tagName: "div",
className: "post",
initialize: function () {
this.post = this.model;
this.render();
},
render: function () {
$(this.el).html(this.template(this.post));
return this;
}
});
view:
ListPost = Backbone.View.extend({
tagName: "div",
className: "listpost",
initialize: function(models, options){
this.listpost = options.listpost;
this.render();
},
render: function () {
_.each(this.listpost, function (post) {
$(this.el).append(new Post({model: post}).el);
}, this);
return this;
}});
route:
var AppRouter = Backbone.Router.extend({
initialize: function () {
$('body').html(new ListPost([], {listpost: posts}).el);
window.onscroll = this.scroll;
},
scroll : function() {
var element = $('.post');
var find_out = false;
for(var i = 0; i< element.length; i++) {
if(find_out) break;
var post = element[i];
if(post.getBoundingClientRect) {
var rect = post.getBoundingClientRect();
x = rect.bottom;
y = rect.top;
if(x > 0) {
if(x > 480/3) {
//result is post
// how i can select this post to sub view Post
find_out = true;
}
}
}
}
}});
Move the scroll functionality to the ListPost so you can have an array of views in your scope.
Example:
ListPost = Backbone.View.extend({
tagName: "div",
className: "listpost",
initialize: function(models, options){
this.listpost = options.listpost;
// Add scroll event here ($.proxy makes sure the event can see this.element).
$(document).scrool( $.proxy(this.scroll, this) );
this.render();
// Create an array to hold a reference to all Post views.
this.element = [];
},
render: function () {
_.each(this.listpost, function (post) {
// Create the post views and add them to the array.
var postView = new Post({model: post});
this.element.push( postView );
$(this.el).append(postView.el);
}, this);
return this;
},
scroll: function() {
var find_out = false;
// Make sure you use this with element.
for(var i = 0; i< this.element.length; i++) {
if(find_out) break;
// Post is now a Backbone view.
var post = this.element[i];
// Make sure you use post.el to access the views DOM element.
if(post.el.getBoundingClientRect) {
var rect = post.el.getBoundingClientRect();
x = rect.bottom;
y = rect.top;
if(x > 0) {
if(x > 480/3) {
//result is post
// how i can select this post to sub view Post
find_out = true;
// Do what you want with the backbone view.
post.render();
console.log(post.model);
}
}
}
}
}
});

Trigger invokes the called function multiple time when fired from layout view in marionitte

I am using marionitte framework and i am trying to fire a trigger from one layout view to any other view but its function on the other view is invoked multiple times even though the trigger is fired only once.
Does anyone has got encountered the same issue and has resolved it please let me know the resolution so that i can use in my code.
w.src.SourceTabView = Backbone.Marionette.Layout.extend({
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template: "#src-template-source-tab-view",
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
regions: {
"change results" : "#src-template-change-results-region",
"change pagination" : "#src-template-change-pagination-region",
"document layout" : "#src-template-document-layout-region",
"workflow detail" : "#src-template-workflow-detail-region",
"job log" : "#src-template-job-log-region",
"source job" : "#src-template-job-region"
},
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
changeInfo: null,
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
mostRecentChange: null,
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
screenCapture: null,
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
regionSelector: null,
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
tab: "details",
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
controls: {
institution: new w.EntitySelector(null,[]),
contentSetGroup: new w.EntitySelector(null,["cs"]),
pageTypes: new w.EntitySelector(null,["page_type"]),
prevTypes: new w.EntitySelector(null,["previous_type"])
},
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
initialize: function(){
this.listenTo( this.model , 'sync' , this.render );
var instTypes = [] ;
for( var instTypeEntityId in w.INST_TYPES ){
instTypes.push(instTypeEntityId);
}
this.controls.institution = new w.EntitySelector(null,instTypes);
this.controls.institution.minValueLength = 1;
this.controls.contentSetGroup.maxValueLength = 1;
this.controls.contentSetGroup.minValueLength = 1;
this.controls.prevTypes.minValueLength = 1;
this.controls.prevTypes.maxValueLength = 1;
this.fetchMostRecentChange();
this.regionSelector = null;
this.changeInfo = new w.src.ChangeInfo(this.model);
this.changeInfo.vent.on("change-selected", this.render);
this.changeInfo.vent.on("change-refreshed", this.render);
this.changeInfo.vent.on("workflow-selected", this.render);
this.changeInfo.vent.on("workflow-refreshed", this.render);
this.changeInfo.vent.on("jobLog-view", this.render);
this.changeInfo.vent.on("workflow-created", w.refreshWorkflows);
this.changeInfo.vent.on('save-source', this.fromJobRun, this);
},
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
fetchMostRecentChange: function(){
var self = this;
$.ajax({
url: "/source/" + self.model.id + "/most-recent-change",
dataType: "json",
success: function(mostRecentChange){
if( mostRecentChange ){
$.ajax({
url: "/document?change=" + mostRecentChange.id + "&rendering=screen-capture",
dataType: "json",
success: function(response){
self.mostRecentChange = mostRecentChange;
if( response.results.length > 0 ){
self.screenCapture = response.results[0];
}
self.render.call(self);
}
});
}
}
});
},
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
serializeData: function(){
var verificationDate = this.model.get('verificationDate');
// Converting timestamp into readable format
if(!verificationDate) {
verificationDate = '';
} else {
verificationDate = moment(verificationDate).format('MM/DD/YYYY');
}
return {
model: this.model,
tab: this.tab,
minimumChangeInterval: this.humanizeDate(this.model.get("minimumChangeIntervalMs")),
verificationDate: verificationDate
}
},
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
onRender: function(){
var tabRegion = localStorage.getItem("tabRegion"),
rememberTabs = localStorage.getItem("rememberTabs");
if( tabRegion && rememberTabs === "true"){
this.tab = tabRegion;
} else if( this.tab == null ) {
this.tab = "details";
}
localStorage.setItem("tabRegion", this.tab);
// content set group
var contentSetIds = [];
for( var contentSetId in w.CS ){
if( this.model.get("entityIds").indexOf(contentSetId) >= 0 ){
contentSetIds.push(contentSetId);
}
}
this.controls.contentSetGroup.values = contentSetIds;
this.controls.contentSetGroup.bind(this.$("#src-tab-details-group"));
// page types
var pageTypeIds = [];
for( var pageTypeId in w.PAGE_TYPES ){
if( this.model.get("entityIds").indexOf(pageTypeId) >= 0 ){
pageTypeIds.push(pageTypeId);
}
}
this.controls.pageTypes.values = pageTypeIds;
this.controls.pageTypes.bind(this.$("#src-tab-details-page"));
// prev types
var prevTypeIds=[];
for(var prevTypeId in w.PREV_TYPES){
if(this.model.get("entityIds").indexOf(prevTypeId)>=0){
prevTypeIds.push(prevTypeId);
}
}
this.controls.prevTypes.values = prevTypeIds;
this.controls.prevTypes.bind(this.$("#src-tab-details-previousType"));
// changes
var changePaginationView = new w.PaginationView({collection:this.changeInfo.changes});
changePaginationView.autoHide = true;
this["change results"].show(new w.src.ChangeCollectionView({collection:this.changeInfo.changes, changeInfo:this.changeInfo}));
this["change pagination"].show(changePaginationView);
// institution
var institutionIds = [];
_.each(this.model.get("entityIds"),function(entityId){
if( !w.INST_TYPES[entityId] && !w.PAGE_TYPES[entityId] && !w.CS[entityId] && !w.PREV_TYPES[entityId]){
institutionIds.push(entityId);
}
});
this.controls.institution.values = institutionIds;
this.controls.institution.bind(this.$("#src-tab-details-institution"));
// job
this["source job"].show(new w.src.SourceJobView({changeInfo:this.changeInfo}));
// documents
if( this.changeInfo.selectedChange ){
var documentLayoutView = new w.src.DocumentLayoutView({collection:this.changeInfo.documents, changeInfo:this.changeInfo});
this["document layout"].show(documentLayoutView);
var documentPaginationView = new w.PaginationView({collection:this.changeInfo.documents});
documentPaginationView.autoHide = true;
documentLayoutView["document results"].show(new w.src.DocumentCollectionView({collection:this.changeInfo.documents, changeInfo:this.changeInfo}));
documentLayoutView["document pagination"].show(documentPaginationView);
} else {
this["document layout"].close();
}
//view job logs
if(this.changeInfo.viewDetails) {
var self = this;
var jobId = this.changeInfo.selectedChange.get('jobId');
var selectedJobModel = new w.Job({id: jobId});
selectedJobModel.fetch({ success: function(model) {
self["job log"].show(new w.src.JobLogView({logger: model.get('logger')}));
}});
}
// workflow detail
this["workflow detail"].show(new w.src.WorkflowDetailView({changeInfo:this.changeInfo}));
// other setup
this.onUrlType();
this.setTab();
if(!this.model.isNew()) {
this.validate();
}
if(this.model.get("includedRegions").length) {
this.$(".delete-all-selected-region").removeClass("disabled");
}
// Adding datepicker
this.$("#verificationDate").datepicker({
todayHighlight: true,
autoclose: true
});
},
fromJobRun: function() {
var self = this;
this.onUseMyAccountClick();
this.populateDateToModel();
// save the model
this.model.save().success(function() {
self.onSuccess();
self.changeInfo.vent.trigger("job-selected");
}).error(function(response) {
self.onError(response)
});
},
});
sourceJobView.js
w.src.SourceJobView = Backbone.Marionette.Layout.extend({
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template: "#src-template-source-job-view",
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
initialize: function(){
this.options.changeInfo.vent.on("job-selected", this.runJob );
},
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
onRender : function(){
// decide whether to show the job details link
if( w.IS_ADMIN ){
this.$(".jobDetailsMessage").show();
} else {
this.$(".jobDetailsMessage").hide();
}
} ,
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
serializeData: function(){
return this.options.changeInfo;
},
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
runJob: function() {
console.log('here');
},
onRunJobClick: function() {
this.options.changeInfo.vent.trigger("save-source");
}
});
According to the code here
Onrunjobclick in sourceJobview triggered is fired to sourceTabview which is listened by fromrunJob which on success fires a trigger back to sourceJobview which is listened by runJob which is invoked multiple times
The most common cause of this issue is zombie views - they have been removed from the DOM, but their event handlers remain bound.
You should use listenTo instead of on to bind events. This allows Marionette's View.close method to clean up old event handlers when views are closed.
It's a simple fix:
initialize: function(){
this.listenTo(options.changeInfo.vent, "job-selected", this.runJob);
},

Backbone.Js events from subview doesn't fire

I'm new to BackboneJs. And I really don't know what hell I'm doing wrong, but the events from my subview doesn't fire. I've been stuck with this problem now a long time, and I've used the google and stackoverflow to find a solution to my problem but I'm still confused. Could someone help\guide me?
var ExerciseList = Backbone.Collection.extend();
var ExerciseView = Backbone.View.extend({
events : {
'click' : "clickFun"
},
clickFun : function(e) {
alert("yamaha");
},
render : function() {
var exerciseList = new ExerciseList();
exerciseList.url = '/api/exercise_bank/' + this.id + '/';
var that = this;
var element = this.$el;
exerciseList.fetch({
success : function() {
var template = _.template($('#exercise-bank-template-exercises').html(), {exercises : exerciseList.models});
$(element).html(template);
}
});
return this;
},
});
// Collection
var MuscleGroupList = Backbone.Collection.extend({
url : '/api/exercise_bank/'
});
// View
var MuscleGroupView = Backbone.View.extend({
el : '#exercise-bank-component',
initialize : function() {
this.exerciseList = new ExerciseList();
this.exerciseView = new ExerciseView();
},
render : function() {
var muscleGroupList = new MuscleGroupList();
that = this;
console.log('MuscleGroup.render');
muscleGroupList.fetch({
success : function(muscleGroupList) {
template = _.template($('#exercise-bank-template-musclegroups').html(), {
musclegroups : muscleGroupList.models
});
that.$el.html(template);
_.each(muscleGroupList.models, function(musclegroup) {
var element = "#eb-exercises-" + musclegroup.get('id');
that.exerciseList.id = musclegroup.get('id');
that.exerciseView.id = musclegroup.get('id');
that.exerciseView.setElement(element).render();
return that;
});
}
});
return this;
},
});
muscleGroupView = new MuscleGroupView();
exerciseView = new ExerciseView();
muscleGroupView.render();
Backbone.history.start();
Questions:
1) Is your view getting rendered on the Dom.
2) Is this element really present inside the dom var element = "#eb-exercises-" + musclegroup.get('id');
3) Why do need the setElement here
that.exerciseView.setElement(element).render();
Solved it!
I just moved:
initialize : function() {
this.exerciseList = new ExerciseList();
this.exerciseView = new ExerciseView();
},
down to:
_.each(muscleGroupList.models, function(musclegroup) {
var element = "#eb-exercises-" + musclegroup.get('id');
var exerciseList = new ExerciseList();
var exerciseView = new ExerciseView();
exerciseList.id = musclegroup.get('id');
exerciseView.setElement(element).render();
return that;
});
and now it works as I want it to do! :)

loop through array in each()

I have a backbone chat web app , i have a javascript array which holds names and other stuff, what i want is to look in this array if this.name() exists and if so read the element before the name wich is a image url and use that in option_h3 in the code below.
hope im clear enough.
thanks i.a.
var PeopleView = Backbone.View.extend({
className: 'peopleView',
initialize: function() {
this.people = Hula.user.get("people");
this.people.on('add', this.addPerson, this);
this.people.on('remove', this.render, this);
$(".nav_item").removeClass("nav_item_s");
$("#people_nav").addClass("nav_item_s");
},
render: function(){
this.$el.empty();
var header = $('<div id="people_header">');
var title = $('<div class="t34 title">');
title.html("Friends");
header.append(title);
this.$el.append(header);
var addOption = $('<div id="people_add_option">');
var addInput = '<div id="addp"><div id="people_add_input_h"><form id="add_person_input_form" ><input id="add_person_input" name="s" type="text" value="Enter Hularing ID..." ></input></form></div></div>';
addOption.html(addInput);
this.$el.append(addOption);
var list = $('<div id="people_list" >');
this.$el.append(list);
this.people.each(this.addPerson, this);
return this;
},
addPerson: function(person){
var view = new PeopleViewPerson({model: person});
this.$("#people_list").prepend(view.render().$el);
},
events: {
'keypress #add_person_input': 'addNewPerson',
},
addNewPerson: function(e){
var ID = $('#add_person_input').val();
if(ID !=="Enter Hularing ID..."){
if(e.which == 13) {
if(validate(ID)){
Hula.subscribe(ID);
this.$('#add_person_input').val("")
$("#add_person_input_form")[0].reset();
$('#add_person_input').blur().focus();
e.preventDefault();
}
}
}
}
});
var PeopleViewPerson = Backbone.View.extend({
className: 'friend_holder',
initialize: function() {
$(this.el).attr('id', jid_to_id(this.model.get("jid")));
this.model.on('all', this.render, this);
this.model.get('conversation').get('messages').on('add', this.onNewMessage, this);
},
render: function() {
var img = $('<div class="friend_img_h">');
if(this.pic() == null){
img.html('<img src="farax/img/default.png" />');
} else {
var img_src = 'data:'+this.picType()+';base64,'+this.pic();
img.html('<img src="'+img_src+'" />')
}
var info_h = $('<div class="friend_info_h">');
var person_name = $('<div class="friend_name">');
person_name.html(this.name());
var line2 = $('<div class="friend_line2">');
var status = this.status();
line2.html(status);
var option_h = $('<div class="friend_option_h">');
option_h.html('<div class="msg_person_icon" ></div>');
// CONTACT INFO DIV.
var option_h1 = $('<div class="friend_option_h1">');
// CONTACT INFO IMAGE IN CSS FILE.
option_h1.html('<div class="msg_person_icon1"></div>');
// CONTACT FACEBOOK TIJDLIJN.
var option_h2 = $('<div class="friend_option_h2">');
// CONTACT FACEBOOK TIJDLIJN IMAGE IN CSS FILE.
option_h2.html('<div class="msg_person_icon2"></div>');
var option_h3 = $('<div class="friend_option_h3">');
option_h3.html('<div class="msg_person_icon3"></div>');
for(var t = 0; t < javaScript_array.length; t++) {
// this one stays the same
var naam = this.name();
var res = javaScript_array[t];
// ignore this it is done to get the name from the database the same as in the collection
var naam1 = naam.replace(" ","0");
// see if it exists
if(naam1 === res){
option_h3.append('<div class="msg_person_icon3"><img src="'+ javaScript_array[t-1] +'" width="35" height="35"/></div>');
} else {
option_h3.html('<div class="msg_person_icon3"></div>');
}
}
if(this.ask()== "subscribe"){
line2.prepend('<span class="pending_out">Request pending.</span>');
}
if(this.pending()){
line2.prepend('<span class="pending_in">Pending authorisation!</span>');
}
info_h.append(person_name).append(line2);
this.$el.html(img);
this.$el.append(info_h);
this.$el.append(option_h);
this.$el.append(option_h1);
this.$el.append(option_h2);
this.$el.append(option_h3);
return this;
},
jid: function() { return this.model.get('jid');},
name: function() { return this.model.get('name'); },
status: function() { return this.model.get('status'); },
pic: function() { return this.model.get('picture').pic; },
picType: function() { return this.model.get('picture').picType; },
ask: function() { return this.model.get('ask'); },
subscription: function() { return this.model.get('subscription'); },
pending: function() { return this.model.get('pending'); },
online: function() { return this.model.get('online'); },
events: {
'click .friend_img_h': 'loadPerson',
'click .friend_info_h': 'loadPerson',
'click .msg_person_icon': 'messagePerson'
},
loadPerson: function(){
Hula.screen.person.render(this.model);
},
messagePerson: function(){
Hula.screen.conversation.render(this.model);
},
onAll: function(person){
},
onNewMessage: function(message){
$('#people_list #'+jid_to_id(this.jid())+' .friend_line2').html(message.get("message"));
},
OnStatusChange: function(change){
$("#people_list #"+id_to_jid(this.ji())).html(this.status().toString());
}
});
it only works on the last element in the array while there are three elements.
I'm looking at your code and to be completely honest, it makes absolutely no sense to me.
I can see that you have option1 option2 and option3 which I assume are the 3 elements you are referring to only, in your array at the bottom, you only ever seem to change option 3.

Categories

Resources