angular-schema-form AddOn using the new builder - angular-schema-form

I'm trying to write an AddOn using the new builder. So far so good, but I'm not getting it to listen to schema.format.
It's a simple datepicker using ui-bootstrap.
angular.module('angularSchemaFormUiDatepicker', [
'ui.bootstrap',
'schemaForm',
'templates',
'pascalprecht.translate'
]).config(function(schemaFormProvider, schemaFormDecoratorsProvider, sfBuilderProvider, sfPathProvider) {
var addOn = schemaFormDecoratorsProvider.defineAddOn(
'bootstrapDecorator', // Name of the decorator you want to add to.
'datepicker', // Form type that should render this add-on
'src/templates/angular-schema-form-ui-datepicker.html', // Template name in $templateCache
sfBuilderProvider.stdBuilders // List of builder functions to apply.
);
schemaFormProvider.prependRule('string', function(name, schema, options) {
if (schema.format === 'datepicker') {
// dirty workaround here
if (schema['x-schema-form']) {
schema['x-schema-form'].type = 'datepicker';
} else {
schema['x-schema-form'] = {
type: 'datepicker'
}
}
var f = schemaFormProvider.stdFormObj(name, schema, options);
f.key = options.path;
f.type = 'datepicker';
options.lookup[sfPathProvider.stringify(options.path)] = f;
return f;
}
});
});

Related

override pivot view _render function in custom module odoo 11

I want to override "_render: function ()" function from pivot_renderer.js file in web but not working in custom module. Here is the code i am implementing in my custom module:-
odoo.define('MY_CUSTOM_MODULE_NAME.renderer', function (require) {
"use strict";
var PivotRenderer = require('web.PivotRenderer');
var field_utils = require('web.field_utils');
var core = require('web.core');
var _t = core._t;
PivotRenderer.include({
init: function(parent, state, params) {
this._super.apply(this, arguments);
},
_render: function () {
if (!this._hasContent()) {
// display the nocontent helper
this.replaceElement(QWeb.render('PivotView.nodata'));
return this._super.apply(this, arguments);
}
if (!this.$el.is('table')) {
// coming from the no content helper, so the root element has to be
// re-rendered before rendering and appending its content
this.renderElement();
}
var $fragment = $(document.createDocumentFragment());
var $table = $('<table>').appendTo($fragment);
var $thead = $('<thead>').appendTo($table).addClass("CLASS_NAME");
var $tbody = $('<tbody>').appendTo($table);
var nbr_measures = this.state.measures.length;
var nbrCols = (this.state.mainColWidth === 1) ?
nbr_measures :
(this.state.mainColWidth + 1) * nbr_measures;
for (var i=0; i < nbrCols + 1; i++) {
$table.prepend($('<col>'));
}
this._renderHeaders($thead, this.state.headers);
this._renderRows($tbody, this.state.rows);
// todo: make sure the next line does something
$table.find('.o_pivot_header_cell_opened,.o_pivot_header_cell_closed').tooltip();
this.$el.html($table.contents());
return this._super.apply(this, arguments);
},
});
});
In the above, i want to add a class in the header for calling my custom css "var $thead = $('').appendTo($table).addClass("CLASS_NAME");" with this syntax but it is not reflecting in my custom module. Although, for testing, I have implemented same class in default web module and it is working fine. The issue is in custom module.
So how to solve this issue? Is there any other way for calling class or i am doing it in a wrong way?
var $thead = $('').addClass("CLASS_NAME").appendTo($table);
This will work in my case. You can try it.

Autocomplete off on Angular Directive for Date Picker

I have a directive for JQuery Date picker which injects date picker into input HTML control. This was developed by a previous developer and I am pretty new to Angular at this moment.
My question is that is there any way to prevent showing auto complete on all the date pickers that we inject via this directive?
export class DanialDatePickerDirective implements ControlValueAccessor {
constructor(protected el: ElementRef, private renderer: Renderer) { }
#Input() dateformat: string = "DD-MMM-YY";
#Input() ngModel: any;
#Input() setDefaultDate: boolean;
onModelChange: Function = () => { };
onModelTouched: Function = () => { };
writeValue(value: any) {
if (value) {
var ff = new Date(value);
$(this.el.nativeElement).datepicker("setDate", ff);
}
else {
$(this.el.nativeElement).datepicker("setDate", "");
}
}
registerOnChange(fn: Function): void {
this.onModelChange = fn;
}
registerOnTouched(fn: Function): void {
this.onModelTouched = fn;
}
onBlur() {
this.onModelTouched();
}
ngAfterViewInit() {
var self = this;
$(this.el.nativeElement).datepicker({
dateFormat: 'dd-M-y',
changeMonth: true,
changeYear: true,
showOtherMonths: true,
selectOtherMonths: true
});
if (this.setDefaultDate) {
var ff = new Date(self.ngModel);
setTimeout(function () {
$(self.el.nativeElement).datepicker("setDate", ff);
}, 200);
}
$(this.el.nativeElement).on('change', (e: any) => {
var model = e.target.value;
var date = null;
var monthstring = '';
if (model.indexOf("-") > 0){
monthstring = model.substring(model.indexOf("-") + 1, 5);
}
if (isNaN(parseInt(monthstring))) {
var tt = moment(model, "DD-MMM-YY").format('YYYY-MM-DD');
date = tt;
model = moment(model, "DD-MMM-YYYY").format('MM-DD-YYYY')
}
else {
date = moment(model, "DD-MM-YYYY").format('YYYY-MM-DD');
model = moment(model, "DD-MM-YYYY").format('MM-DD-YYYY')
}
$(".ui-datepicker a").removeAttr("href");
self.onModelChange(date);
self.writeValue(date.toString());
});
}
}
The only approach who works for me:
First, make sure to set autocomplete="off" on both, the input element itself and the parent form.
Second, make sure to assign an unique name to your input field always.
This can be achieved by simply generating a random number and using this number in the name of the field.
private getUniqueName() {
return Math.floor(Math.random() * Date.now());
}
Explanation:
In the past, many developers would add autocomplete="off" to their
form fields to prevent the browser from performing any kind of
autocomplete functionality. While Chrome will still respect this tag
for autocomplete data, it will not respect it for autofill data.
https://developers.google.com/web/updates/2015/06/checkout-faster-with-autofill.
So autocomplete="off" solves the autocomplete issue. But to solve the autofill you need to play dirty with the browser by changing the name of the input over an over again, that way the browser will never know how to autofill ;)

textfield or textarea with in rowbodytpl of extjs grid (rowexpander)

How can I create textfield or textarea with in rowbodytpl of extjs grid (rowexpander). Also my program needs to read these fields and update the DB. I would love to know the use of radiogroup within rowbodytpl
I guess the best way is to implement plugin which can render any component into rowbody. Then you can just pass any component config to it.
Example plugin:
Ext.define('Ext.ux.grid.SubCmp', {
extend: 'Ext.grid.plugin.RowExpander',
alias: 'plugin.subcmp',
rowBodyTpl: ['{%this.owner.renderComponent(out, values);%}'],
// override this method and return component config
componentConfigFn: function(record) { return {}; },
init: function(grid) {
var me = this,
store = grid.getStore(),
view = grid.getView();
me.components = {};
me.callParent(arguments);
// when grid is reloaded we should destroy all created components
grid.on('beforedestroy', me.destroyComponents, me);
store.on('beforeload', me.destroyComponents, me);
// renders component
view.on('expandbody', me.onExpandBody, me);
// modify getRefItems method of grid to allow querying components from rowbody
grid.getRefItems = (function() {
var originalFn = grid.getRefItems;
return function(deep) {
var result = originalFn.call(grid, deep);
if (deep) {
for (var i in me.components) {
result.push(me.components[i]);
result.push.apply(result, me.components[i].getRefItems(true));
}
}
return result;
}
}());
},
destroyComponents: function() {
var me = this,
components = me.components;
for (var i in components) {
components[i].destroy();
}
me.components = {};
},
onExpandBody: function(rowNode, record, expandRow, eOpts) {
var me = this,
grid = me.grid,
recordId = record.id,
componentWrapId = grid.id + '-component-wrap-' + recordId,
component = me.components[recordId];
if (component && !component.rendered) {
component.render(componentWrapId);
}
},
renderComponent: function (out, rowValues) {
var me = this,
grid = me.grid,
store = grid.getStore(),
recordId = rowValues.id,
record = store.getById(recordId),
componentWrapId = grid.id + '-component-wrap-' + recordId,
componentId = grid.id + '-component-' + recordId,
component,
config;
if (me.components[recordId]) {
return; // already rendered
}
config = Ext.apply({}, { id: componentId }, me.componentConfigFn(record));
me.components[recordId] = component = Ext.create(config);
out.push('<div id="' + componentWrapId + '"></div>');
}
});
To select components from rowbody, you can use grid.query method.
Fiddle: http://jsfiddle.net/znnqxmyq/9/

accessing items in firebase

I'm trying to learn firebase/angularjs by extending an app to use firebase as the backend.
My forge looks like this
.
In my program I have binded firebaseio.com/projects to $scope.projects.
How do I access the children?
Why doesn't $scope.projects.getIndex() return the keys to the children?
I know the items are in $scope.projects because I can see them if I do console.log($scope.projects)
app.js
angular.module('todo', ['ionic', 'firebase'])
/**
* The Projects factory handles saving and loading projects
* from localStorage, and also lets us save and load the
* last active project index.
*/
.factory('Projects', function() {
return {
all: function () {
var projectString = window.localStorage['projects'];
if(projectString) {
return angular.fromJson(projectString);
}
return [];
},
// just saves all the projects everytime
save: function(projects) {
window.localStorage['projects'] = angular.toJson(projects);
},
newProject: function(projectTitle) {
// Add a new project
return {
title: projectTitle,
tasks: []
};
},
getLastActiveIndex: function () {
return parseInt(window.localStorage['lastActiveProject']) || 0;
},
setLastActiveIndex: function (index) {
window.localStorage['lastActiveProject'] = index;
}
}
})
.controller('TodoCtrl', function($scope, $timeout, $ionicModal, Projects, $firebase) {
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
var keys = $scope.projects.$getIndex();
console.log($scope.projects.$child('-JGTmBu4aeToOSGmgCo1'));
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("" + keys[0]);
});
// A utility function for creating a new project
// with the given projectTitle
var createProject = function(projectTitle) {
var newProject = Projects.newProject(projectTitle);
$scope.projects.$add(newProject);
Projects.save($scope.projects);
$scope.selectProject(newProject, $scope.projects.length-1);
};
// Called to create a new project
$scope.newProject = function() {
var projectTitle = prompt('Project name');
if(projectTitle) {
createProject(projectTitle);
}
};
// Called to select the given project
$scope.selectProject = function(project, index) {
$scope.activeProject = project;
Projects.setLastActiveIndex(index);
$scope.sideMenuController.close();
};
// Create our modal
$ionicModal.fromTemplateUrl('new-task.html', function(modal) {
$scope.taskModal = modal;
}, {
scope: $scope
});
$scope.createTask = function(task) {
if(!$scope.activeProject || !task) {
return;
}
console.log($scope.activeProject.task);
$scope.activeProject.task.$add({
title: task.title
});
$scope.taskModal.hide();
// Inefficient, but save all the projects
Projects.save($scope.projects);
task.title = "";
};
$scope.newTask = function() {
$scope.taskModal.show();
};
$scope.closeNewTask = function() {
$scope.taskModal.hide();
};
$scope.toggleProjects = function() {
$scope.sideMenuController.toggleLeft();
};
// Try to create the first project, make sure to defer
// this by using $timeout so everything is initialized
// properly
$timeout(function() {
if($scope.projects.length == 0) {
while(true) {
var projectTitle = prompt('Your first project title:');
if(projectTitle) {
createProject(projectTitle);
break;
}
}
}
});
});
I'm interested in the objects at the bottom
console.log($scope.projects)
Update
After digging around it seems I may be accessing the data incorrectly. https://www.firebase.com/docs/reading-data.html
Here's my new approach
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
console.log(snapshot.val()['-JGTdgGAfq7dqBpSk2ls']);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
I'm still not sure how to traverse the keys programmatically but I feel I'm getting close
It's an object containing more objects, loop it with for in:
for (var key in $scope.projects) {
if ($scope.projects.hasOwnProperty(key)) {
console.log("The key is: " + key);
console.log("The value is: " + $scope.projects[key]);
}
}
ok so val() returns an object. In order to traverse all the children of projects I do
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
var keys = Object.keys(snapshot.val());
console.log(snapshot.val()[keys[0]]);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
Note the var keys = Object.keys() gets all the keys at firebaseio.com/projects then you can get the first child by doing snapshot.val()[keys[0])

Loading content dynamically (panels) in an Ext Js Viewport

Well basically im looking on this problem, i have many components with dinamic stuff that is written in the server side with PHP.
Depending on the user my components will change, based on the role of the user.
So i need to know any ways/examples/info on how to do this.
1- I used the load function EXTJS has, but it clearly says i wont load script only plain text.
2- i used eval() but im a bit scared o this approach, like this example crate layout component (static)
var contentPanel = new Ext.Panel({
frame: true,
style: {marginTop: '10px'},
height: 315,
border: true,
bodyBorder: false,
layout: 'fit',
id: 'contentPanel'
});
var mainPanel = new Ext.Panel({
title: 'Panel Principal',
id: 'mainPanel',
border: true,
frame: true,
width: '50%',
style: {margin: '50px auto 0 auto'},
height: 400,
renderTo: Ext.getBody(),
items: [
{
html: 'Panel 1'
},
{
html: 'Panel 2'
},
contentPanel
]
})
and update the content of the layout with js files written on the server
function receiveContent(options, success, response)
{
var respuesta = response.responseText;
//console.log(respuesta);
eval(respuesta);
//console.log(options.url);
url = options.url;
url = url.substring(0,(url.search(/(\.)/)));
var contenedor = Ext.getCmp('contentPanel');
contenedor.removeAll();
var contenido = Ext.getCmp(url);
contenedor.add(contenido);
contenedor.doLayout();
}
function requestContent(panel)
{
//panel es el nombre del archivo que quiero
Ext.Ajax.request({
url: panel+'.js',
callback: receiveContent
});
}
any other way for this to be done, what i DONT want to do is making a million different components and load them ALL at login time like many people seem to say
To address your questions:
The .load method WILL load script and evaluate it once the content has finished loading, however to accomplish this you will need to set the scripts:true option, an example may be:
my_panel.load({
url: 'url_to_load.php/hmt/html/asp...',
params: {param1: param1value, param2: param2value...etc},
nocache: true,
timeout: 30,
scripts: true
});
Using eval() is fine...but seeing as the scripts:true config option above accomplishes this for javascript in the source file, you shouldnt need to use this.
Hope this helps
You might load JavaScript dynamically using something like like below - there are a hundred variations on the web. In this way, you would avoid the AJAX call and handling the response (and subsequent eval).
var aHeadNode = document.getElementById('head')[0];
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = "someFile.js";
aHeadNode.appendChild(oScript);
What I understood from your question is that, you are looking for dynamic JS file loader with a callback handler i.e. the callback function will be called only when the file is loaded fully. I also faced similar problems at start and after searching a lot and doing some research, I developed the following code, it provides absolute Dynamic JS and CSS file loading functionality :
Class ScriptLoader: (Put it in a separate file and load it at first)
ScriptLoader = function() {
this.timeout = 30;
this.scripts = [];
this.disableCaching = false;
};
ScriptLoader.prototype = {
processSuccess : function(response) {
this.scripts[response.argument.url] = true;
window.execScript ? window.execScript(response.responseText) : window
.eval(response.responseText);
if (response.argument.options.scripts.length == 0) {
}
if (typeof response.argument.callback == 'function') {
response.argument.callback.call(response.argument.scope);
}
},
processFailure : function(response) {
Ext.MessageBox.show({
title : 'Application Error',
msg : 'Script library could not be loaded.',
closable : false,
icon : Ext.MessageBox.ERROR,
minWidth : 200
});
setTimeout(function() {
Ext.MessageBox.hide();
}, 3000);
},
load : function(url, callback) {
var cfg, callerScope;
if (typeof url == 'object') { // must be config object
cfg = url;
url = cfg.url;
callback = callback || cfg.callback;
callerScope = cfg.scope;
if (typeof cfg.timeout != 'undefined') {
this.timeout = cfg.timeout;
}
if (typeof cfg.disableCaching != 'undefined') {
this.disableCaching = cfg.disableCaching;
}
}
if (this.scripts[url]) {
if (typeof callback == 'function') {
callback.call(callerScope || window);
}
return null;
}
Ext.Ajax.request({
url : url,
success : this.processSuccess,
failure : this.processFailure,
scope : this,
timeout : (this.timeout * 1000),
disableCaching : this.disableCaching,
argument : {
'url' : url,
'scope' : callerScope || window,
'callback' : callback,
'options' : cfg
}
});
}
};
ScriptLoaderMgr = function() {
this.loader = new ScriptLoader();
this.load = function(o) {
if (!Ext.isArray(o.scripts)) {
o.scripts = [o.scripts];
}
o.url = o.scripts.shift();
if (o.scripts.length == 0) {
this.loader.load(o);
} else {
o.scope = this;
this.loader.load(o, function() {
this.load(o);
});
}
};
this.loadCss = function(scripts) {
var id = '';
var file;
if (!Ext.isArray(scripts)) {
scripts = [scripts];
}
for (var i = 0; i < scripts.length; i++) {
file = scripts[i];
id = '' + Math.floor(Math.random() * 100);
Ext.util.CSS.createStyleSheet('', id);
Ext.util.CSS.swapStyleSheet(id, file);
}
};
this.addAsScript = function(o) {
var count = 0;
var script;
var files = o.scripts;
if (!Ext.isArray(files)) {
files = [files];
}
var head = document.getElementsByTagName('head')[0];
Ext.each(files, function(file) {
script = document.createElement('script');
script.type = 'text/javascript';
if (Ext.isFunction(o.callback)) {
script.onload = function() {
count++;
if (count == files.length) {
o.callback.call();
}
}
}
script.src = file;
head.appendChild(script);
});
}
};
ScriptMgr = new ScriptLoaderMgr();
Now it can be used this way:
For CSS files loading :
ScriptMgr.loadCss([first.css', 'second.css']);
That is you just need to provide css files path in an array and pass that array to loadCss() function as an argument. No callback is required for CSS files.
For JS file loading :
ScriptMgr.load({
scripts : ['lib/jquery-1.4.2.min.js','lib/jquery.touch-gallery-1.0.0.min.js'],
callback : function() {
//Here you will do those staff needed after the files get loaded
},
scope : this
});
In this case, the same way you entered CSS files, here you just need to put that array of JS files in scripts option. The callback function is called only when all the JS files are loaded successfully. Also, if in any case, the JS files are already loaded in the browser (i.e. already this code is run once), then the control will automatically go to the callback function.

Resources