Calling a jquery function within a view B from a view A - javascript

I have a view in my asp.net mvc4 web app from which user can configure some things related to it. When user click on a button in this view, let's say, configure view, I want to call a jquery function in another view, let's say, main view. This jquery function is in charge of modifying an element in the main view.
In the configure view where button is, I have below code, some input textboxes and the button (this calls to action AddItem in Configure controller):
#using (Html.BeginForm("AddItem", "Configure", FormMethod.Post))
{
#Html.DropDownListFor(m => m.CustomViewModel.SelectedItemId, Model.CustomViewModel.ListItems)
#Html.TextBox(...)
<input id="submitAdd" type="submit" value="#Resource.ButtonTitleAdd" />
}
So how to do call a jquery function in main view from the above code when user clicks on the button on configure view?
Also I need to pass to this jquery function the value select in the dropdown list of configure view. For example, if dropdown list contains:
"something1"
"something2"
"something3"
I need to pass the value of the item selected in the dropdownlist. For example, if user selects "something1" and its value is 1, 1 should be passed to this jquery function. This dropdown list is populated with a model.

I would have solved it with a custom event, which you can trigger and listen to from where ever you like.
Trigger it like this:
$.event.trigger('customStuff', [arg1, arg2, argN]);
And "listen" for it like this:
$(document).on('customStuff', function (e, arg1, arg2) { });

As you are using jQuery. I think something like pubsub is your best bet & it encourages event based loose coupling. For example:
(function($) {
var o = $({});
$.subscribe = function() {
o.on.apply(o, arguments);
};
$.unsubscribe = function() {
o.off.apply(o, arguments);
};
$.publish = function() {
o.trigger.apply(o, arguments);
};
}(jQuery));
Now you can use this code as following:
// You can pass your custom data here
$.subscribe("firefunction", function(e, a, b, c) {
console.log(a + b + c);
});
$.publish("firefunction", [ "a", "b", "c" ]);
// logs: abc
// Unsubscribe all handlers for this topic
$.unsubscribe("firefunction");

Related

How to inherit Odoo's POS buttons

I'm trying to add some functions in the POS buttons, specifically the button that shows up like "Validate". To test if the guide in this link https://odoo-development.readthedocs.io/en/latest/dev/pos/gui.html works, I'm just adding a console.log like the following:
odoo.define('my_module.js_file', function (require) {
"use strict";
var screens = require('point_of_sale.screens');
screens.PaymentScreenWidget.include({
init: function(parent, options) {
this._super(parent, options);
//My console log message
console.log('Hello world!')
this.pos.on('updateDebtHistory', function(partner_ids){
this.update_debt_history(partner_ids);
}, this);
},
});
But the message only shows up once when the POS ends loading the data and not when I push the button. What am I doing wrong here?
To add your code to the Validate button you will need to modify the payment screen widget via the include method (You already did that).
If you inspect the button from the browser you will find that it has a class next which is used to bind an event handler to the click JavaScript event.
Example:
var screens = require('point_of_sale.screens');
var PaymentScreenWidget = screens.PaymentScreenWidget;
PaymentScreenWidget.include({
validate_order: function(force_validation) {
console.log('Hello world!');
this._super(force_validation);
},
});

Odoo field doesn't update when changed from javascript with an RPC call

I want to be able to change the context of a one2many field (work_unit) programatically to modify the default value of one of its fields (product_id).
Ideally I would like to change the o2m context directly from my widget, but I haven't had any success doing that, the view doesn't acknowledge any changes I make from javascript.
Current approach: I have another field selected_chapter which I pass through context as the default for work_unit.product_id. This works fine: when I change selected_chapter manually, the o2m context picks up the new default for the field product_id.
Now, I want to be able to modify selected_chapter programatically from a widget in javascript.
I do this by calling a python method with an _rpc() call from my widget, and it works, but the view doesn't update selected_chapter until I save the record which defeats the purpose of the call.
Widget code:
ListRenderer.include({
...
_setSelectedChapter: function () {
var self = this;
this.trigger_up('mutexify', {
action: function () {
return self._rpc({
model: 'sale.order',
method: 'set_selected_chapter',
args: [
[self.res_id]
],
kwargs: {
chapter_id: self.filter.getSelected()
},
}).then(function (result) {
console.log("res", result);
self._render();
});
},
});
},
...
})
Model code:
selected_chapter = fields.Many2one('product.product')
#api.multi
def set_selected_chapter(self, chapter_id):
chapter = self.env['product.product'].browse(chapter_id)
if not chapter.exists():
return
# I've also tried using self.update(), same results
self.selected_chapter = chapter
View code:
<field name="work_unit" mode="tree,kanban" filter_field="product_id" context="{'default_product_id': selected_chapter}">
First, rename work_unit to work_unit_ids.
Then, on the server side write an onchange method. See https://www.odoo.com/documentation/12.0/reference/orm.html#onchange-updating-ui-on-the-fly

Same RadioButton-Setting Function from Both Startup / Change in jQuery

I have a single shared jQuery function that checks a RadioButton selection: if 1 is selected, it hides a span, otherwise it shows it.
This shared function is called both on startup and on Change, because on startup, it needs to do the same thing. The startup works, but the onChange reference does NOT work:
JS_OBJ = {
toggleTier : function() {
if ($('input[name="tier"]:checked').val() == 'Y_YES')
{
$('#tierSpan').hide();
}
else
{
$('#tierSpan').show();
}
},
// this is called from document.onReady - it comes here, OK
onReady : function() {
// on startup, toggle Tier - works OK
this.toggleTier();
// Also link the radio button Change to this shared function
$('input[name="tier"]:radio').change(function () {
alert('About to enter toggle...');
// NEVER COMES HERE - Object doesn't support this property or method
this.toggleTier();
});
}
};
the this is changing value as it is passing thru the different zones. when it is first instantiated, it has a good value, but the radiobutton:change has a different this
I was able to change it get it to work:
$('input[name="tier"]:radio').change(function () {
alert('About to enter toggle...');
self; //closure
toggleTier();
});
see this: What underlies this JavaScript idiom: var self = this?
Inside the change event, this does not refer to the current JS_OBJ, it refers to the current event target in stead. You want to explicitly save your reference to this, so you can use it inside the event.
Example:
onReady : function() {
var me = this;
me.toggleTier();
// Also link the radio button Change to this shared function
$('input[name="tier"]:radio').change(function () {
me.toggleTier();
});
}

How to reload json data in acitree

I would like to know whether there is any possible way to refresh an aciTree instance from a json object received from the server.
Let's assume I have an html input field.
The user types something and clicks the submit button.
This input is used to get a new version of the json tree model from the server through an ajax call.
That works fine. However, when I type again a new value in the input field and submit the aciTree does not reflect the new values. It still displays the old json object data.
Here is my code.
User Name: <input type="input" id="name" name="name">
<input type="submit" value="search" id="call" >
<script type="text/javascript">
$(document).ready(function(){
// Makes the ajax call and fetches the json for the resource tree.
$('#call').click(function(){
$("#tree").aciTree({
ajax: {
url: 'treeview/jsp/testplansjson.jsp?sname='+document.getElementById("name").value+',
}
});
});
// Refreshing the tree view - Destroy and recreate
$('#call').click(function(){
var api = $('#tree').aciTree('api');
api.unload(null, {
success: function() {
this.ajaxLoad(null);
// Triggering the click handler of the Get Tree View button.
// This will make the ajax call again and bind the tree...
$('#call').trigger('click');
}
});
});
// ACI Tree - event handler.
$('#tree').on('acitree', function(event, aciApi, item, eventName, opt) {
switch (eventName) {
case 'focused':
case 'selected' :
// Fired when an item in the tree is selected.
if(item) {
$currStatus.text('Selected - ' + item.context.innerText);
}
}
});
});
</script>
<div id="tree" class="aciTree aciTreeNoBranches aciTreeFullRow" style="width:100%;height:auto;margin:0;padding:0;border-left:0;border-right:0"></div>
Please let me know whether there is any way to achieve this.
$(_selector_).aciTree(_options_) call will init the tree view just once (using the provided options). Nothing will happen if you call it twice. To be able to init the tree view with other options, you'll need to destroy it first.
In your case, you need just to update the tree view ajax.url option. First unload the tree, then reload it from the new url.
To update one of the aciTree options at runtime, use the option method. Note that you can use the dot notation to reach deep level properties:
api.option('ajax.url', '_your_new_url_');
Then you can call unload/ajaxLoad (as in your example).
<script type="text/javascript">
$(document).ready(function(){
// Makes the ajax call and fetches the json for the resource tree.
$('#call').click(function(){
$("#tree").aciTree({
ajax : {
url: 'treeview/jsp/testplansjson.jsp?sname='+document.getElementById("name").value+',
}
});
});
// Refreshing the tree view - Destroy and recreate
$('#call').click(function(){
var api = $('#tree').aciTree('api');
api.unload(null, {
success: function() {
this.ajaxLoad(null);
// Triggering the click handler of the Get Tree View button.
// This will make the ajax call again and bind the tree...
$('#call').trigger('click');
}
});
});
// ACI Tree - event handler.
$('#tree').on('acitree', function(event, aciApi, item, eventName, opt) {
switch (eventName) {
case 'focused':
case 'selected' :
// Fired when an item in the tree is selected.
if(item) {
$currStatus.text('Selected - ' + item.context.innerText);
}
}
});
});
</script>
<div id="tree" class="aciTree aciTreeNoBranches aciTreeFullRow" style="width:100%;height:auto;margin:0;padding:0;border-left:0;border-right:0"></div>

Create a generic class to bind knockout object with pages

I am bit new to knockout and jquery mobile, There was a question which is already answered, I need to optimize the PageStateManager class to use generic bindings, currently PageStateManager can only use for one binding,I would really appreciate if someone can guide me to create a generic class to manage page states with knockout bindings Heere is the working code,http://jsfiddle.net/Hpyca/14/
PageStateManager = (function () {
var viewModel = {
selectedHospital: ko.observable()
};
var changePage = function (url, viewModel) {
console.log(">>>>>>>>" + viewModel.id());
$.mobile.changePage(url, {viewModel: viewModel});
};
var initPage = function(page, newViewModel) {
viewModel.selectedHospital(newViewModel);
};
var onPageChange = function (e, info) {
initPage(info.toPage, info.options.viewModel);
};
$(document).bind("pagechange", onPageChange);
ko.applyBindings(viewModel, document.getElementById('detailsView'));
return {
changePage: changePage,
initPage: initPage
};
})();
Html
<div data-role="page" data-theme="a" id="dashBoardPage" data-viewModel="dashBoardViewModel">
<button type="button" data-bind="click: goToList">DashBoard!</button>
</div>
New dashboard model
var dashBoardViewModel = function() {
var self = this;
self.userName = ko.observable('Welcome! ' + "UserName");
self.appOnline = ko.observable(true);
self.goToList = function(){
//I would like to use PageStateManager here
// PageStateManager.changePage($("#firstPage"),viewModel);
ko.applyBindings(viewModel,document.getElementById("firstPage"));//If I click Dashbord button multiple times it throws and multiple bind exception
$.mobile.changePage($("#firstPage"));
}
}
ko.applyBindings(dashBoardViewModel,document.getElementById("dashBoardPage"));
update url : http://jsfiddle.net/Hpyca/14/
Thank you in advance
I would probably go for creating a NavigationService which only handles changing the page and let knockout and my view models handle the state of the pages.
An simple example of such a NavigationService could be:
function NavigationService(){
var self = this;
self.navigateTo = function(pageId){
$.mobile.changePage($('#' + pageId));
};
}
You could then, in your view models just call it when you want it to navigate to a new page. One example would be upon selection of a hospital (which could be done either via a selection function or by manually subscribing to changes to the selectedHospital observable):
self.selectHospital = function(hospital){
self.selectedHospital(hospital);
navigationService.navigateTo('detailsView');
};
Other than the call to the navigationService to navigate, it's just ordinary knockout to keep track of which viewmodel should be bound where. A lot easier than having jquery mobile keeping track of which viewmodel goes where, if you ask me.
I have updated your jsfiddle to show a sample of how this could be done, making as few changes as possible to the HTML code. You can find the updated fiddle at http://jsfiddle.net/Hpyca/15/

Categories

Resources