Form view in odoo 12 - javascript

In my custom module, there is one relation field. After click on create and edit form view is pop up. But I didn’t want to open this form view as a popup. I want to open this form view in the current window or in the current form. This is possible in odoo 12 or by using javascript Please, anyone, help me.
Thanks in advance.
Edit
Model and view are defined as per odoo instruction as :
class SurveySurvey(models.Model):
_name = 'survey.survey'
pages_ids = fields.One2many('survey.page','survey_id', string='Pages', copy=True)
View:
<field name="pages_ids" mode="tree" context="{'default_survey_id': active_id}" options="{'no_open':False}">
<tree editable="bottom" >
<field name="title"/>
<field name="question_ids" class="question_ids_class" widget="many2many_tags" context="{'page_id': active_id}" domain="[('page_id','=','active_id')]" options="{'no_open':true,'no_quick_create':true}"/>
</tree>
</field>
question_id is a relation field after click on create and edit option available in relation field one popup is open javascript code for that pop is as follows:
_searchCreatePopup: function (view, ids, context) {
var self = this;
return new dialogs.SelectCreateDialog(this, _.extend({}, this.nodeOptions, {
res_model: this.field.relation,
domain: this.record.getDomain({fieldName: this.name}),
context: _.extend({}, this.record.getContext(this.recordParams), context || {}),
title: (view === 'search' ? _t("Search: ") : _t("Create: ")) + this.string,
initial_ids: ids ? _.map(ids, function (x) { return x[0]; }) : undefined,
initial_view: view,
disable_multiple_selection: true,
no_create: !self.can_create,
on_selected: function (records) {
self.reinitialize(records[0]);
self.activate();
}
})).open();
},
The above code is available in web/static/js/fields/relational_fields.js
For better understanding please see screenshots.
Screenshot after click on Create and edit

Related

send the value of the field from an interactive grid to another page and store it in an item with Javascript and Oracle Apex

Good evening, I currently save the value of a field of the grid in an item (P5_VALUE),send it to another page (page 6) and store it in an item (P6_VALUE) through a button
Action: Redirect to Page in this application.
Target: Page in this application , Page: 6, set Items: NAME: P5_VALUE, VALUE: P6_VALUE, Action: Reset Pagination. This is the url that is generated: http://ip:port/ords/app/system/page?p5_value=61&clear=RP&session=12518184703789
But now I want to do the same with APEX$ROW_SELECTOR. With this code I have been able to add an action to the grid and get the value of the field but I do not know how to send it to the other page and assign the value to the other item
var view = apex.region("ig-emp").widget().interactiveGrid("getViews", "grid"),
menu$ = view.rowActionMenu$;
menu$.menu("option").items.push({
type:"action",
label:"Get Emp No",
icon: "fa fa-close",
action: function(menu, element) {
var record = view.getContextRecord( element )[0];
var val1 = view.model.getValue(record, "EMPNO");
}
});
Por favor su ayuda, gracias
Use the below approach to achieve this:
Let me start by adding some more lines to your code.
var view = apex.region("ig-emp").widget().interactiveGrid("getViews", "grid"),
menu$ = view.rowActionMenu$;
menu$.menu("option").items.push({
type:"action",
label:"Get Emp No",
icon: "fa fa-close",
action: function(menu, element) {
var record = view.getContextRecord( element )[0];
var val1 = view.model.getValue(record, "EMPNO");
apex.page.submit({
request:"NAVIGATE",
set:{"P1_EMPNO":val1},
showWait: true
});
}
});
Note: in the above code replace P1_EMPNO with your page item name.'
Create a Branch -> Type: Page or URL(Redirect).
Select the page number to redirect and set the value of the current page item to the new page item. Refer below screen shot for example.
In the Server-side condition, select the Type as Request = Value and provide the value as NAVIGATE. Refer below screen shot.

show FormView inside a Widget in Odoo 10

Can I create a Widget which gets model name as a parameter and renders model's form view?
My expectation is like:
When a user clicks a menu, the models form is displayed in edit mode ('mymodule.asset_category').
The user then selects a category dropdown. For example 'Asset'. ('Asset' asset_category's 'related_model' field is type of 'ir.model' and it's value would be 'mymodule.asset')
new form which makes the user able to create new related model's ('mymodule.asset') instance is created inside the parent form.
The user fills asset fields and then clicks the Save button.
Thus 'mymodule.asset_category', 'mymodule.asset' objects are saved to the database.
I think I can achieve these using wizards by showing forms sequentially. But I want to know at least if it's achievable in this way.
I tried following way:
class AssetCategory(models.Model):
_name = 'mymodule.asset_category'
name = fields.Char(string=u'Category', required="True")
related_model = fields.Many2one('ir.model', string=u'Related model')
class Asset(models.Model):
_name = 'mymodule.asset'
name = fields.Char(string=u'Asset Name', required="True")
amount = fields.Float(string=u'Amount', digit=[12, 2])
XML will be like:
<record model="ir.ui.view" id="asset_form_view">
<field name="name">mymodule_asset_form</field>
<field name="model">mymodule.asset_category</field>
<field name="arch" type="xml">
<form string="asset category">
<sheet>
<field name="name"></field>
<field name="related_model"></field>
<widget type="my_widget"></widget>
</sheet>
</form>
</field>
</record>
And the Javascript:
'mymodule.asset' parameter will be set dynamically onchange of "related_model" dropdown.
var MyWidget = Widget.extend({
start:function(){
self = this;
var dataset = new data.DataSet(this, 'mymodule.asset');
var v_id;
dataset._model.call('get_formview_id', [[0], {}]).then(function (view_id) {
v_id = view_id
});
var fields_view_def;
fields_view_def = data_manager.load_fields_view(dataset, v_id, 'form', false);
var form_view = new FormView(self, dataset, fields_view_def, {});
return form_view.appendTo(this.$el);
}
});
core.form_custom_registry.add('my_widget', MyWidget);
My current code throws following error:
http://localhost:8069/web/static/src/js/views/form_view.js:1239
Алдааны мөр:
TypeError: Cannot read property 'attrs' of undefined
at Class.set_fields_view (http://localhost:8069/web/static/src/js/views/form_view.js:1239:49)
at Class.start (http://localhost:8069/web/static/src/js/views/form_view.js:97:31)
at Class.prototype.<computed> [as start] (http://localhost:8069/web/static/src/js/framework/class.js:89:38)
at http://localhost:8069/web/static/src/js/framework/widget.js:193:25
at http://localhost:8069/web/static/lib/jquery/jquery.js:3276:89
at fire (http://localhost:8069/web/static/lib/jquery/jquery.js:3119:58)
at Object.add [as done] (http://localhost:8069/web/static/lib/jquery/jquery.js:3165:49)
at Array.<anonymous> (http://localhost:8069/web/static/lib/jquery/jquery.js:3275:77)
at Function.each (http://localhost:8069/web/static/lib/jquery/jquery.js:383:58)
at Object.<anonymous> (http://localhost:8069/web/static/lib/jquery/jquery.js:3272:56)
As I know you are familiar with Odoo, you have heard about hr_timesheet_sheet module.
for your reference you can check out this module.
hr_timesheet_sheet:-
https://github.com/odoo/odoo/blob/10.0/addons/hr_timesheet_sheet/static/src/js/timesheet.js

How do I populate a list field in a model from javascript?

I have a Kendo.MVC project. The view has a model with a field of type List<>. I want to populate the List from a Javascript function. I've tried several ways, but can't get it working. Can someone explain what I'm doing wrong?
So here is my model:
public class Dashboard
{
public List<Note> ListNotes { get; set; }
}
I use the ListNotes on the view like this:
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
}
This works if I populate Model.ListNotes in the controller when the view starts...
public ActionResult DashBoard(string xsr, string vst)
{
var notes = rep.GetNotesByCompanyID(user.ResID, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
Dashboard employee = new Dashboard
{
ResID = intUser,
Type = intType,
FirstName = user.FirstName,
LastName = user.LastName,
ListNotes = listNotes
};
return View(employee);
}
... but I need to populate ListNotes in a Javascript after a user action.
Here is my javascript to make an ajax call to populate ListNotes:
function getReminders(e)
{
var userID = '#ViewBag.CurrUser';
$.ajax({
url: "/api/WoApi/GetReminders/" + userID,
dataType: "json",
type: "GET",
success: function (notes)
{
// Need to assign notes to Model.ListNotes here
}
});
}
Here's the method it calls with the ajax call. I've confirmed ListNotes does have the values I want; it is not empty.
public List<Koorsen.Models.Note> GetReminders(int id)
{
var notes = rep.GetNotesByCompanyID(id, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
foreach (Koorsen.OpenAccess.Note note in notes)
{
Koorsen.Models.Note newNote = new Koorsen.Models.Note()
{
NoteID = note.NoteID,
CompanyID = note.CompanyID,
LocationID = note.LocationID,
NoteText = note.NoteText,
NoteType = note.NoteType,
InternalNote = note.InternalNote,
NoteDate = note.NoteDate,
Active = note.Active,
AddBy = note.AddBy,
AddDate = note.AddDate,
ModBy = note.ModBy,
ModDate = note.ModDate
};
listNotes.Add(newNote);
}
return listNotes;
}
If ListNotes was a string, I would have added a hidden field and populated it in Javascript. But that didn't work for ListNotes. I didn't get an error, but the text on the screen didn't change.
#Html.HiddenFor(x => x.ListNotes)
...
...
$("#ListNotes").val(notes);
I also tried
#Model.ListNotes = notes; // This threw an unterminated template literal error
document.getElementById('ListNotes').value = notes;
I've even tried refreshing the page after assigning the value:
window.location.reload();
and refreshing the panel bar the code is in
var panelBar = $("#IntroPanelBar").data("kendoPanelBar");
panelBar.reload();
Can someone explain how to get this to work?
I don't know if this will cloud the issue, but the reason I need to populate the model in javascript with an ajax call is because Model.ListNotes is being used in a Kendo Panel Bar control and I don't want Model.ListNotes to have a value until the user expands the panel bar.
Here's the code for the panel bar:
#{
#(Html.Kendo().PanelBar().Name("IntroPanelBar")
.Items(items =>
{
items
.Add()
.Text("View Important Notes and Messages")
.Expanded(false)
.Content(
#<text>
#RenderReminders()
</text>
);
}
)
.Events(e => e
.Expand("getReminders")
)
)
}
Here's the helper than renders the contents:
#helper RenderReminders()
{
if (Model.ListNotes.Count <= 0)
{
#Html.Raw("No Current Messages");
}
else
{
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
<br />
}
}
}
The panel bar and the helpers work fine if I populate Model.ListNotes in the controller and pass Model to the view. I just can't get it to populate in the javascript after the user expands the panel bar.
Perhaps this will do it for you. I will provide a small working example I believe you can easily extend to meet your needs. I would recommend writing the html by hand instead of using the helper methods such as #html.raw since #html.raw is just a tool to generate html in the end anyways. You can write html manually accomplish what the helper methods do anyway and I think it will be easier for you in this situation. If you write the html correctly it should bind to the model correctly (which means it won't be empty on your post request model) So if you modify that html using javascript correctly, it will bind to your model correctly as well.
Take a look at some of these examples to get a better idea of what I am talking about:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
So to answer your question...
You could build a hidden container to hold your list values like this (make sure this container is inside the form):
<div id="ListValues" style="display:none">
</div>
Then put the results your ajax post into a javascript variable (not shown).
Then in javascript do something like this:
$('form').off('submit'); //i do this to prevent duplicate bindings depending on how this page may be rendered futuristically as a safety precaution.
$('form').on('submit', function (e) { //on submit, modify the form data to include the information you want inside of your ListNotes
var data = getAjaxResults(); //data represents your ajax results. You can acquire and format that how you'd like I will use the following as an example format for how you could save the results as JSON data: [{NoteID ="1",CompanyID ="2"}]
let listLength = data.length;
for (let i = 0; i < listLength; i++) {
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].NoteID " value="' + data.NoteID +'" />')
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].CompanyID " value="' + data.CompanyID +'" />')
//for your ajax results, do this for each field on the note object
}
})
That should do it! After you submit your form, it should automatically model bind to you ListNotes! You will be able to inpsect this in your debugger on your post controller action.

AngularJS - Get printed value from scope inside an attribute?

I'm currently working on an AngularJS project and I got stuck in this specific requirement.
We have a service that has all the data, DataFactoryService. Then, I have a controller called DataFactoryController that is making the magic and then plot it in the view.
<div ng-repeat = "list in collection">
{{list.name}}
...
</div>
Now, we have a requirement that pass multiple data into one element. I thought an "ng-repeat" would do, but we need to have it inside an element attribute.
The scenarios are:
At one of the pages, we have multiple lists with multiple data.
Each data has a unique code or ID that should be passed when we do an execution or button click.
There are instances that we're passing multiple data.
Something like this (if we have 3 items in a list or lists, so we're passing the 3 item codes of the list):
<a href = "#" class = "btn btn-primary" data-factory = "code1;code2;code3;">
Submit
</a>
<a href = "#" class = "btn btn-default" data-factory = "code1;code2;code3;">
Cancel
</a>
In the example above, code1,code2,code3 came from the list data. I tried several approach like "ng-repeat", "angular.each", array, "ng-model" but I got no success.
From all I've tried, I knew that "ng-model" is the most possible way to resolve my problem but I didn't know where to start. the code below didn't work though.
<span ng-model = "dataFactorySet.code">{{list.code}}</span>
{{dataFactorySet.code}}
The data is coming from the service, then being called in the controller, and being plot on the HTML page.
// Controller
$scope.list = dataFactoryService.getAllServices();
The data on the list are being loaded upon initialization and hoping to have the data tags initialized as well together with the list data.
The unique code(s) is/are part of the $scope.list.
// Sample JSON structure
[
{ // list level
name: 'My Docs',
debug: false,
contents: [ // list contents level
{
code: 'AHDV3128',
text: 'Directory of documents',
...
},
{
code: 'AHDV3155',
text: 'Directory of pictures',
...
},
],
....
},
{ // list level
name: 'My Features',
debug: false,
contents: [ // list contents level
{
code: 'AHGE5161',
text: 'Directory of documents',
...
},
{
code: 'AHGE1727',
text: 'Directory of pictures',
...
},
],
....
}
]
How can I do this?
PLUNKER -> http://plnkr.co/edit/Hb6bNi7hHbcFa9RtoaMU?p=preview
The solution for this particular problem could be writing 2 functions which will return the baseId and code with respect to the list in loop.
I would suggest to do it like below
Submit
Cancel
//inside your controller write the methods -
$scope.getDataFactory = function(list){
var factory = list.map( (a) => a.code );
factory = factory.join(";");
return factory;
}
$scope.getDataBase= function(list){
var base= list.map( (a) => a.baseId);
base= base.join(";");
return base;
}
Let me know if you see any issue in doing this. This will definitely solve your problem.
You don't really have to pass multiple data from UI if you are using Angular.
Two-way data binding is like blessing which is provided by Angular.
check your updated plunker here [http://plnkr.co/edit/mTzAIiMmiVzQfSkHGgoU?p=preview]1
What I have done here :
I assumed that there must be some unique id (I added Id in the list) in the list.
Pass that Id on click (ng-click) of Submit button.
You already have list in your controller and got the Id which item has been clicked, so you can easily fetch all the data of that Id from the list.
Hope this will help you... cheers.
So basing from Ashvin777's post. I came up with this solution in the Controller.
$scope.getFactoryData = function(list) {
var listData = list.contents;
listData = listData.map(function(i,j) {
return i.code;
});
return listData.join(';');
}

How to update data in Meteor using Reactivevar

I have a page with a form. In this form user can add multiple rows with key and values. There is a restriction that the customFields is created on the fly, not from any subscribed collection.
...html
<template name="main">
{{#each customFields}}
<div>
<input type="text" value="{{key}}"/>
<input type="text" style="width: 300px;" value="{{value}}"/>
</div>
{{/each}}
</template
.... router.js
Router.route 'products.add',
path: '/products/add/:_id'
data:
customFields:[]
....products.js
#using customFieldSet as Reactive Var from meteor package
Template.product.created = ->
#customFieldSet = new ReactiveVar([])
Template.product.rendered = ->
self = this
Tracker.autorun ->
arr = self.customFieldSet.get()
self.data.customFields = arr
Template.product.events(
'click .productForm__addField': (e)->
t = Template.instance()
m = t.customFieldSet.get()
console.log t
m.push(
key: ''
value: ''
)
t.customFieldSet.set m
....
The last event will be trigger when I click the button. And it add another row with key and value empty to the page.
Please advise me why I actually see the reactive variable customFieldSet updated, but there is nothing changed dynamically in html.
P/s: I guess customFields is not updated via Iron router.
Basically, you're doing the thing right. However, you shouldn't be assigning the new reactive data to your template's data context, but rather access it directly from your helpers:
Template.product.helpers({
customFileds: function () {
return Template.instance().customFiledsSet.get();
},
});
Now you can use {{customFields}} in your template code and it should work reactively. Just remember that {{this.customFileds}} or {{./customFileds}} will not work in this case.

Categories