this is an original function from Framework I'm working with. It's a Python-based framework with a little bit Javascript. and as I do not really know much about JS I want to ask a question.
How can I override init: function (parent, options) part.
in that function, I need to change just one thing.
line 57
link
display_order: ORDER.ASC to ORDER.DESC
so i need somehow to call this functions in super and change arguments
var Thread = Widget.extend({
className: 'o_mail_thread',
events: {
"click a": "on_click_redirect",
"click img": "on_click_redirect",
"click strong": "on_click_redirect",
"click .o_thread_show_more": "on_click_show_more",
"click .o_thread_message_needaction": function (event) {
var message_id = $(event.currentTarget).data('message-id');
this.trigger("mark_as_read", message_id);
},
"click .o_thread_message_star": function (event) {
var message_id = $(event.currentTarget).data('message-id');
this.trigger("toggle_star_status", message_id);
},
"click .o_thread_message_reply": function (event) {
this.selected_id = $(event.currentTarget).data('message-id');
this.$('.o_thread_message').removeClass('o_thread_selected_message');
this.$('.o_thread_message[data-message-id=' + this.selected_id + ']')
.addClass('o_thread_selected_message');
this.trigger('select_message', this.selected_id);
event.stopPropagation();
},
"click .oe_mail_expand": function (event) {
event.preventDefault();
var $message = $(event.currentTarget).parents('.o_thread_message');
$message.addClass('o_message_expanded');
this.expanded_msg_ids.push($message.data('message-id'));
},
"click .o_thread_message": function (event) {
$(event.currentTarget).toggleClass('o_thread_selected_message');
},
"click": function () {
if (this.selected_id) {
this.unselect();
this.trigger('unselect_message');
}
},
},
init: function (parent, options) {
this._super.apply(this, arguments);
this.options = _.defaults(options || {}, {
display_order: ORDER.ASC,
display_needactions: true,
display_stars: true,
display_document_link: true,
display_avatar: true,
shorten_messages: true,
squash_close_messages: true,
display_reply_icon: false,
});
this.expanded_msg_ids = [];
this.selected_id = null;
},
If you're unable or not interested in changing the source code, you can pass
{display_order: ORDER.DESC} as the options parameter when creating this class.
Related
I made this JS to add a functionality on a form (backend) that computes a field when the event click is triggered. So far the code recomputes when I use ".include" but the whole JS in all views fail since I'm using ".include". When I try to use extend my code does nothing. Looks like Odoo doesn't add the extended code to the JS engine so my question is, what am I doing wrong here? Is there something else I need to add so my code works as extended?
odoo.define('med_care.TestRenderer', function (require) {
"use strict";
var viewRegistry = require('web.view_registry');
var FormRenderer = require('web.FormRenderer');
var FormView = require('web.FormView');
var TestFormRenderer = FormRenderer.extend({
events: _.extend({}, FormRenderer.prototype.events, {
'click .sign_selector': '_onSignSelectorClicked',
}),
init: function (parent, state, params) {
this._super.apply(this, arguments);
this.fields = state.fields;
this._onSignSelectorClicked = _.debounce(this._onSignSelectorClicked, 300, true);
},
confirmChange: function (state, id, fields, e) {
var self = this;
if (state.model == 'med.test') {
return this._super.apply(this, arguments).then(function () {
self.canBeSaved(self.state.id);
});
}
},
_onSignSelectorClicked: function (event) {
this.state.data.telephone = '333';
if (this.state.model == 'med.test') {
var info_test = {
dataPointID: this.state.id,
changes: {telephone: '333'},
viewType: "form",
notifyChange: true
};
var odoo_event = this.trigger_up('field_changed', info_test);
this.confirmChange(this.state, this.state.id, "telephone",
odoo_event)
}
},
});
var TestFormView = FormView.extend({
config: _.extend({}, FormView.prototype.config, {
Renderer: TestFormRenderer,
}),
});
viewRegistry.add('test_form', TestFormView);
return TestFormView;
});
I have an issue with Odoo V12 Javascript Framework.
I don't know whather the javascript is loaded or there is another issue:
odoo.define('titi.Home',['web.core','web.Dialog','web.Class'], function(require) {
"use strict";
var core = require('web.core'),
Dialog = require('web.Dialog'),
Class = require('web.Class');
var TitiHouse = Dialog.extend({
template: 'titi.her_house_name',
events: {
'click a#titi_s_house_name a': '_onClick',
},
init: function(parent, params) {
var self = this;
var options = _.extend({
size: 'large',
buttons: [{
text: params.titi_s_house_name,
click: self._onClick,
classes: 'btn-secondary',
}],
}, params || {});
self._super(parent, options);
},
_onClick: function(event) {},
willStart: function() {
console.log('Will start .....');
},
start: function() {
console.log('Start !!!');
},
});
return TitiHouse;
});
When can I execute this javascript file in template?
Or how to execute that script in template?
There are a couple of things that could be contributing to the problem:
1 - You are not calling the super methods of the Dialog widget in willStart or start. Try making these:
...
willStart: function() {
console.log('Will start .....');
return this._super.apply(this, arguments);
},
start: function() {
console.log('Start !!!');
return this._super.apply(this, arguments);
},
...
2 - You are not extending the events, you are overridding them. You need to make your events param:
events: _.extend({}, Dialog.prototype.events, {
'click a#titi_s_house_name a': '_onClick',
}),
Try changing these and see if it helps.
My controller code is here.
spine.module("communityApp", function (communityApp, App, Backbone, Marionette, $, _) {
"use strict";
communityApp.Controllers.pforumController = Marionette.Controller.extend(
{
init: function(){
var func = _.bind(this._getpforum, this);
var request = App.request('alerts1:entities' , {origin:'pforum'});
$.when(request).then(func)
},
_getpforum:function(data){
var pforumCollectionView = new communityApp.CollectionViews.pforumCollectionViews({
collection: data
});
communityApp.activeTabView = pforumCollectionView;
// Populating the data
communityApp.activeTabLayout.pforum.show(pforumCollectionView);
},
});
});
view code is here
spine.module("communityApp", function (communityApp, App, Backbone, Marionette, $, _) {
// Load template
var a;
var pforumTemplateHtml = App.renderTemplate("pforumTemplate", {}, "communityModule/tabContainer/pforum");
// Define view(s)
communityApp.Views.pforumView = Marionette.ItemView.extend({
template: Handlebars.compile($(pforumTemplateHtml).html()),
tagName: "li",
onRender: function () {
this.object = this.model.toJSON();
},
events: {
"click #postcomment" : "alrt",
"click #recent-btn": "recent",
"click #my-posts": "myposts",
"click #popular-btn": "popular",
"click #follow-btn": "follow",
"click #my-posts": "LeftLinks",
"click #popular-btn": "LeftLinks",
"click #follow-btn": "LeftLinks"
},
postcomments : function ()
{
$("#recent-post-main-container").hide();
$("#recent-post-main-container2").show();
},
alrt : function ()
{
alert ("In Progress ......");
},
showCommentEiditor : function (){
$(".comment-popup-container").show();
$(".comment-txt-area").val('');
},
showPforumTab : function ()
{
$("#recent-post-main-container2").show();
$("#recent-post-main-container").hide();
},
showComments : function(){
$("#loading").show();
$(".tab-pane").hide();
$(".left-content").hide();
$("#recent-post-main-container2").show();
//$(".left-content-commentEditor").show();
$(".comm-tab-content-container").css('height','200px');
$(".comment-txt-area").val('');
$(".left-content-comment").show();
},
hideCommentPopup : function ()
{
$("#public-question-comment").hide();
},
// Show Loading sign
showLoading : function () {
$('#loading').show();
},
// UnLoading Function
hideLoading : function (){
$('#loading').hide();
},
// Add New Event Function
addEvent : function()
{
//$("#name").val(getBackResponse.user.FullName);
//$("#phone").val(getBackResponse.user.CellPhone);
//$("#email").val(getBackResponse.user.UserName);
$(".overly.addevent").show();
$('#lang').val(lat);
$('#long').val(long);
document.getElementById("my-gllpMap").style.width = "100%";
var my_gllpMap = document.getElementById("my-gllpMap");
google.maps.event.trigger( my_gllpMap, "resize" );
},
setValues : function(key,value)
{
window.localStorage.setItem(key,value);
},
getValues : function (key)
{
return window.localStorage.getItem(key);
},
closeAddEvent:function ()
{
$(".overly.addevent").hide();
},
// Show Over lay
showOverly:function ()
{
$('.overly-right-tab').show();
},
// Hide Loading sign
hideOverly : function()
{
$('.overly-right-tab').hide();
},
LeftLinks: function (e) {
var elem = $(e.target).closest('a');
var elem = $(e.target).closest('a');
var event = elem.attr('name');
switch (event) {
case "myposts":
var _this = $.extend({}, this, true);
_this.event = 'myposts';
this.LinkUrl.call(_this);
//$("#my-posts").addClass('active');
//$("#public-fourm-top-tab").addClass('TabbedPanelsTabSelected');
//$(".types").removeClass('active');
break;
case "recents":
var _this = $.extend({}, this, true);
_this.event = 'recents';
this.LinkUrl.call(_this);
$(".types").removeClass('active');
$("#recent-btn").addClass('active')
//$("#pforum").removeClass('active');
// $("#recent").addClass('active');
break;
case "populars":
var _this = $.extend({}, this, true);
_this.event = 'populars';
this.LinkUrl.call(_this);
$(".types").removeClass('active');
$("#popular-btn").addClass('active')
// $("#pforum").removeClass('active');
//$("#popular").addClass('active');
break;
case "follows":
var _this = $.extend({}, this, true);
_this.event = 'follows';
this.LinkUrl.call(_this);
$(".types").removeClass('active');
$("#follow-btn").addClass('active')
break;
}
},
LinkUrl: function (modalThis) {
communityApp.activeTabView.collection = []; // currently empty data
communityApp.activeTabView.render();
className: 'comm-main-container'
// uncomment these lines when getting data fro web service route, it will repopulate the data
var func = _.bind(function (data) {
communityApp.activeTabView.collection = data;
communityApp.activeTabView.render();
}, this);
switch (this.event) {
case "myposts":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
event: this.event
})).then(func);
break;
case "recents":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
event: this.event
})).then(func);
break;
case "populars":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
origin1:'popular',
event: this.event
})).then(func);
break;
case "follows":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
event: this.event
})).then(func);
break;
}
return true;
}
});
// define collection views to hold many communityAppView:
communityApp.CollectionViews.pforumCollectionViews = Marionette.CollectionView.extend({
tagName: "ul",
itemView: communityApp.Views.pforumView
});
});
Whenever I need to share an event between a view and controller I usually wire up the listeners within the module that instantiates the controller. This example is a bit contrived, but it gets the point across. The full working code is in this codepen. The relevant bit is copied here. Notice the line this.listenTo(view, 'itemview:selected', this.itemSelected); where the view's event triggers a method on the controller.
App.module("SampleModule", function(Mod, App, Backbone, Marionette, $, _) {
// Define a controller to run this module
// --------------------------------------
var Controller = Marionette.Controller.extend({
initialize: function(options){
this.region = options.region
},
itemSelected: function (view) {
var logView = new LogView();
$('#log').append(logView.render('selected:' + view.cid).el);
},
show: function(){
var collection = new Backbone.Collection(window.testData);
var view = new CollectionView({
collection: collection
});
this.listenTo(view, 'itemview:selected', this.itemSelected);
this.region.show(view);
}
});
// Initialize this module when the app starts
// ------------------------------------------
Mod.addInitializer(function(){
Mod.controller = new Controller({
region: App.mainRegion
});
Mod.controller.show();
});
});
The other way to accomplish this, if you cannot wire it all up within the same module, is to use Marionette's messaging infrastructure. For example, you can use the application's event aggregator to pass events around.
I'm having trouble in attempting to use two models with the same view in backbone.js. Somehow the view is being rendered before the triggers are getting triggered to begin the render function.
Here are the models:
APP.Models.FamilyPreferences = Backbone.Model.extend({
initialize: function( attributes, options ) {
_.bindAll(this, 'success_handler', 'populate');
this.url = options.url;
},
populate: function(){
this.fetch({success: this.success_handler});
},
success_handler: function(){
this.trigger("change");
}
});
APP.Models.Preferences = Backbone.Model.extend({
initialize: function( attributes, options ) {
_.bindAll(this, 'success_handler', 'error_handler', 'populate');
this.url = options.url;
},
populate: function(){
this.fetch({success: this.success_handler, error:this.error_handler});
},
success_handler: function(){
this.exists = true;
this.trigger("change");
},
error_handler: function(){
this.exists = false;
this.trigger("change");
}
});
Here is the relevant code from the view:
APP.Views.PreferencesFormView = Backbone.View.extend({
templates: [{name:"preferences_template", file_path:"preferences_form.html"}],
initialize: function(options){
_.bindAll(this, 'render', 'renderPrereq');
var family_url = "services/family/" + options.family_id;
var preferences_url = "services/preferences/familyID/" + options.family_id;
var ctx = this;
this.alreadyRendered = false;
this.modelsCurrentlyLoaded = [];
this.models = {};
this.models.family = new APP.Models.FamilyPreferences({}, {url: family_url});
this.models.family.on('change', function(){ctx.renderPrereq("family");});
this.models.family.populate();
this.models.preferences = new APP.Models.Preferences({}, {url:preferences_url});
this.models.preferences.on('change', function() {ctx.renderPrereq("preferences");});
this.models.preferences.populate();
},
renderPrereq: function(newmodel){
var inside = ($.inArray(newmodel, this.modelsCurrentlyLoaded)>-1) ? true : false;
if (!(inside)){this.modelsCurrentlyLoaded.push(newmodel);}
var total = Object.keys(this.models).length;
if(this.modelsCurrentlyLoaded.length == total && !this.alreadyRendered){
this.alreadyRendered = true;
this.render();
}
},
render: function(){
var family_data = {
id: this.models.family.attributes.id,
familyGroup: this.models.family.attributes.groupNum,
familyId: this.models.family.attributes.familyId,
probandDob: this.models.family.attributes.childDob,
}
var preferences_data = {
mother: this.models.preferences.attributes[0],
father: this.models.preferences.attributes[1],
exists: this.models.preferences.exists
}
this.$el.html(this.compiledTemplates.preferences_template(family_data));
//bunch of javascript making the page work
}
});
The template are getting loaded through another js function elsewhere that to the best of my knowledge is working correctly. Somehow the render function is getting called before the success handlers. I can't figure out how. The only side effect it has is that the Preferences model doesn't get the exists property and is hence undefined which cause all sorts of problems. Also, options.family_id is set correctly. Any help would be appreciated. Thank you in advance.
EDIT: It also seems to be going to renderPrereq up to six times which I also can't figure out.
JSON - Family model
{
"id": 1,
"familyId": "family01",
"collectionDate": "2013-01-01",
"childDob": "2001-05-06",
"groupNum": "Two",
"probands": [],
"mother": null,
"father": null,
"siblings": []
}
JSON - First part of Preferences Model
[{
"main": "illness-only",
"obesity": "No",
"bloodPressure": "No",
"diabetes": "No",
"heart": "No",
"alzheimers": "No",
"parkinsons": "No",
"mentalHealth": "No",
"breastOvarianCancer": "No",
"prostateTesticularCancer": "No",
"otherCancer": "No",
"childSickleCell": "No",
"childCysticFibrosis": "No",
"childMuscularDystrophy": "No",
"childAutism": "No"
},
{
"main":"more-questions",
"obesity":"No",
"bloodPressure":"Yes",
"diabetes":"No",
"heart":"Unsure",
"alzheimers":"No",
"parkinsons":"Yes",
"mentalHealth":"No",
"breastOvarianCancer":"No",
"prostateTesticularCancer":"No",
"otherCancer":"No",
"childSickleCell":"No",
"childCysticFibrosis":"No",
"childMuscularDystrophy":"No",
"childAutism":"No"}]
Headers
Accept: application / json, text / javascript, /; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache Connection:keep-alive
Cookie:csrftoken=bDIpdvAPBdWF6dZe9BkpsFSF4wiGl2qX
Host:localhost:8080 Pragma:no-cache Referer:localhost:8080/CSER / index.html
User - Agent: Mozilla / 5.0(Macintosh; Intel Mac OS X 10_8_3) AppleWebKit /
537.36(KHTML, like Gecko) Chrome / 27.0.1453.110 Safari / 537.36 X - Requested - With: XMLHttpRequest
Try this code ..
APP.Models.FamilyPreferences = Backbone.Model.extend({
initialize: function (attributes, options) {
_.bindAll(this, 'success_handler', 'populate');
this.url = options.url;
},
populate: function () {
this.fetch();
},
// This is not required
// It will automatically render it as we are listening to the sync event
success_handler: function () {
// Not required
// sync event will take care of it
}
});
APP.Models.Preferences = Backbone.Model.extend({
initialize: function (attributes, options) {
_.bindAll(this, 'success_handler', 'error_handler', 'populate');
this.url = options.url;
},
populate: function () {
this.fetch({
success: this.success_handler,
error: this.error_handler
});
},
success_handler: function () {
this.exists = true;
// Not required
// sync event will take care of it
},
error_handler: function () {
// Do something else
}
});
APP.Views.PreferencesFormView = Backbone.View.extend({
templates: [{
name: "preferences_template",
file_path: "preferences_form.html"
}],
initialize: function (options) {
_.bindAll(this, 'render', 'renderPrereq');
var family_url = "services/family/" + options.family_id;
var preferences_url = "services/preferences/familyID/" + options.family_id;
var ctx = this;
this.alreadyRendered = false;
this.modelsCurrentlyLoaded = [];
this.models = {};
// Family Model
this.models.family = new APP.Models.FamilyPreferences({}, {
url: family_url
});
this.listenTo( this.models.family, 'change', function () {
ctx.renderPrereq("family");
});
// This will take care of rendering it on Sync with server
// No need to triggereing the event explicitly..
this.listenTo( this.models.family, 'sync', function () {
ctx.renderPrereq("family");
});
this.models.family.populate();
// Family Preference Model
this.models.preferences = new APP.Models.Preferences({}, {
url: preferences_url
});
this.listenTo( this.models.preferences, 'change', function () {
ctx.renderPrereq("family");
});
// This will take care of rendering it on Sync with server
// No need to triggereing the event explicitly..
this.listenTo( this.models.preferences, 'sync', function () {
ctx.renderPrereq("preferences");
});
this.models.preferences.populate();
},
renderPrereq: function (newmodel) {
var inside = ($.inArray(newmodel, this.modelsCurrentlyLoaded) > -1) ? true : false;
if (!(inside)) {
this.modelsCurrentlyLoaded.push(newmodel);
}
var total = Object.keys(this.models).length;
if (this.modelsCurrentlyLoaded.length == total && !this.alreadyRendered) {
this.alreadyRendered = true;
this.render();
}
},
render: function () {
var family_data = this.models.family.toJSON());
var preferences_data = {
mother: this.models.preferences.attributes[0],
father: this.models.preferences.attributes[1],
exists: this.models.preferences.get('exists') ? this.models.preferences.get('exists') : false
}
this.$el.html(this.compiledTemplates.preferences_template(family_data);
//bunch of javascript making the page work
}
});
Looks like the problem is the way it is constructed... I don't think the render is called before success_handler .
If you look at the renderPrereq method , 2 models on change will call this method on success.
But the fetch methods are async. So you never know which handler will be called first.
And when the change on the model is triggered. This calls the render method which is inside the renderPrereq method.
Using the Jeditable plugin,
is possible to create, very easily, a submit and cancel button.
Here's a very simple code example (*)
Now let's suppose in MyView (Backbone.View) I would like to trigger the event click on the button submit which is created by Jeditable.
Here's the code regarding the Backbone.View (**).
When I trigger the event "click .submitBtn" the value of $('.edit_area').text is empty string.
In order to fix this issue I implemented the following code (* **)
Do you have some smart idea to improve the code of (* **)? I don't like callback using setTimeout.
(*)
$('.edit_area').editable(function(value, settings) {
return(value);
}, {
type : 'textarea',
submit : '<div class="submitBtn">Ok</div>'
cancel : '<div class="submitBtn">Undo</div>'
});
(**)
MyView = Backbone.View.extend({
events: {
"click .edit_area" : "edit",
"click .submitBtn" : "close"
},
});
(* **)
close: function close ()
{
var that = this;
console.log($(this.el).find("[data-tid='editable']").text()); // empty string
setTimeout(function () {
console.log($(that.el).find("[data-tid='editable']").text()); // update string
that.model.save({
name: $(that.el).find("[data-tid='editable']").text()
});
}, 0);
},
in the initialize function
$('.edit_area').editable(this.close, {
type : 'textarea',
submit : 'OK',
});
Close function definition
close:function(value, settings) {
this.model.save({
name: value
});
});
Complete Code
var editableview = Backbone.View.extend({
initialize: function () {
_.bind(this.close, this);
},
render: function () {
$(this.el).find('.edit_area').editable(this.close, {
type: 'textarea',
submit: '<div class="submitBtn">Ok</div>'
cancel: '<div class="submitBtn">Undo</div>'
});
},
close: function (value, settings) {
this.model.save({
name: value
});
});
});
Var That = This is wrong. This is the DOM not the backbone view. You can do:
$('.edit_area').editable(this.close, {
type : 'textarea',
submit : 'OK',
submitdata: {view: this},
});
"view" in the hash would be the backbone view. It can be accessed in the close function.
close:function(value, settings) {
settings.submitdata.view.model.save({
name: value
});
});