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.
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;
});
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.
I am getting this error . I am able to preform read, and remove functions using BackboneJs , but i am having error when i execute the add method any help will be appreciated.
JSfiddel path is http://jsfiddle.net/2wjdcgky/
BackboneJS Uncaught Error: A "url" property or function must be specified
$(function() {
Model
var modelContact = Backbone.Model.extend({
defaults: function() {
return {
Id: 0,
Name: "",
Address: ""
};
},
idAttribute: "Id"
});
ModelCollection
var contactCollection = Backbone.Collection.extend({
model: modelContact,
url: function() {
return 'api/Contact';
},
add: function(model) {
this.sync("create", model); // Error On create
},
remove: function(model) {
this.sync("delete", model); //Runs Fine
}
});
var contacts = new contactCollection;
View
var contactView = Backbone.View.extend({
tagName: "tr",
events: {
"click a.destroy": "clear"
},
template: _.template($("#newContacttemplate").html()),
initialize: function() {
this.model.on("change", this.render, this);
this.model.on('destroy', this.remove, this);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
clear: function(e) {
contacts.remove(this.model); // runs fine
}
});
Main View
var main = Backbone.View.extend({
el: $("#contactApp"),
events: {
"click #btnsave": "CreateNewContact"
},
initialize: function() {
this.Nameinput = this.$("#contactname");
this.Addressinput = this.$("#contactaddress");
contacts.on("add", this.AddContact, this);
contacts.on("reset", this.AddContacts, this);
contacts.fetch();
},
AddContact: function (contact) {
console.log("AddContact");
var view = new contactView({ model: contact });
this.$("#tblcontact tbody").append(view.render().el);
},
AddContacts: function () {
console.log("AddContacts");
contacts.each(this.AddContact);
},
CreateNewContact: function (e) {
console.log(e);
//Generate an error "BackboneJS Uncaught Error: A "url" property or function must be specified"
contacts.add({ Name: this.Nameinput.val(), Address: this.Addressinput.val() });
}
});
var m = new main;
});
Your JSFiddle was missing Backbone references and all.
Working update: http://jsfiddle.net/apt7hchL/2/
Much simpler code (no need to define those add and remove methods on the collection!). Also more common Javascript coding style conventions.
Please note I had to manually generate an "Id" attribute to allow creating more than one contact. As you are making Id = 0 by default, second model with same is not added, as Backbone sees a model with id=0 is already in the collection.
When you want to save, call the model.save() method. Don't call sync manually, you'll normally don't need to!
For the model to be saved to the database before being added to the collection, use:
createNewContact: function (e) {
e.preventDefault();
var self = this;
var newContact = new ContactModel({
Name: this.$("#name").val(),
Address: this.$("#address").val()
});
newContact.save({ success: function(model){
self.collection.add(model);
});
//clear form
this.$("#name").val("");
this.$("#address").val("");
}
Sync method tries to sync to a server setup to handle it, with CRUD abilities. If thats not what you're looking for, and you just want to display this information on the client side, instead of using sync, you should use Collection.add(model) and Collection.remove(model)
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 struggling to get a simple master-detail scenario working with Backbone. Here's the jsfiddle and code is below.
Problem 1: this navigation doesn't work at all if I switch "pushstate" to true. What I really want is to have no hashes/pound signs in my urls.
Problem 2: my users might rock up on a url like /accommodation/287, not always on the home page. How would you deal with that using the router?
Thanks a lot for any help!
var AccommodationItem = Backbone.Model.extend({
defaults: {
html: "",
loaded: false
},
urlRoot: "/Home/Accommodation/"
});
var AccommodationItemView = Backbone.View.extend({
tagName: "li",
template: _.template("<a href='#accommodation/<%= id %>'><%= description %></a>"),
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var AccommodationList = Backbone.Collection.extend({
model: AccommodationItem
});
var DetailView = Backbone.View.extend({
initialize: function () { },
render: function () {
this.$el.html(this.model.get("html"));
},
setModel: function (model) {
this.model = model;
var $this = this;
if (!this.model.get("loaded")) {
/*
this.model.fetch({ success: function () {
$this.model.set("loaded", true);
$this.render();
}
});*/
$this.model.set("html", "<h2>Full item " + this.model.get("id") + "</h2>");
$this.model.set("loaded", true);
$this.render();
} else {
$this.render();
}
}
});
var AccommodationListView = Backbone.View.extend({
tagName: "ul",
initialize: function () {
this.collection.on("reset", this.render, this);
},
render: function () {
this.addAll();
},
addOne: function (item) {
var itemView = new AccommodationItemView({ model: item });
this.$el.append(itemView.render().el);
},
addAll: function () {
this.collection.forEach(this.addOne, this);
}
});
var App = new (Backbone.Router.extend({
routes: {
"": "index",
"accommodation/:id": "show"
},
initialize: function () {
this.detailView = new DetailView({ model: new AccommodationItem({ id: 1 }) });
$("#detail").append(this.detailView.el);
this.accommodationList = new AccommodationList();
this.accommodationListView = new AccommodationListView({ collection: this.accommodationList });
$("#app").append(this.accommodationListView.el);
},
start: function () {
Backbone.history.start({ pushState: false });
},
index: function () {
this.fetchCollections();
},
show: function (id) {
var model = this.accommodationList.get(id);
this.detailView.setModel(model);
},
fetchCollections: function () {
var items = [{ id: 1, description: "item one" }, { id: 2, description: "item two" }, { id: 3, description: "item three" }];
this.accommodationList.reset(items);
}
}));
$(function () {
App.start();
});
EDIT: In a comment below I mentioned the Codeschool backbone.js tutorial. Just want to say that I have now finished BOTH parts of the course and it DOES cover exactly the AppView pattern described in the accepted answer. It's an excellent course and I thoroughly recommend it.
you have a few of the concepts mixed up.
There is too much to explain here, so I've (very roughly) put together a patch of your code that works as you intend. I would advise that you put it side-by-side with your own and see what I have done differently.
http://jsfiddle.net/wtxK8/2
A couple of things, you should not init Backbone.history from within a router. your 'init' should look something more like this
$(function () {
window.app = new App();
window.appView = new AppView({el:document});
Backbone.history.start({ pushState: true });
});
This is setting a 'wrapper' view than encompasses the entire page. Also, you have far too much logic in your router. Try to only use the router for routes. After my quick re factor, your router only contains this:
var App = Backbone.Router.extend({
routes: {
"": "index",
"accommodation/:id": "show"
},
show: function (id) {
var model = window.appView.accommodationList.get(id);
window.appView.detailView.setModel(model);
}
});
The AppView (that I have written for you now does all of that initialize work.
var AppView = Backbone.View.extend({
initialize : function(){
this.detailView = new DetailView({ model: new AccommodationItem({ id: 1 }) });
$("#detail").append(this.detailView.el);
this.accommodationList = new AccommodationList();
this.accommodationListView = new AccommodationListView({ collection: this.accommodationList });
$("#app").append(this.accommodationListView.el);
this.fetchCollections();
},
fetchCollections: function () {
var items = [
{ id: 1, description: "item one" },
{ id: 2, description: "item two" },
{ id: 3, description: "item three" }
];
this.accommodationList.reset(items);
}
});
Even after my re factor, it's still far from optimal, but I have provided it all to help you on your journey of learning :)
I would then recommend you follow some of the on-line tutorials step-by-step so that you can set up the structure of your app in a better way.
Good Luck, and be sure to check out http://jsfiddle.net/wtxK8/2 to see it working.
EDIT: I have not address your second question. there is enough to be worked on with question 1 to keep you busy. If I have more time later, I will help further.