I have a few different JavaScript web resources that use the getGrid(), all of which started failing this week after I enabled the 2020 Wave 1 Updates in D365. The error message shows:
"Error occurred :TypeError: Unable to get property 'getGrid' of undefined or null reference"
Here is my code:
function GetTotalResourceCount(executionContext) {
console.log("function started");
var execContext = executionContext;
var formContext = executionContext.getFormContext();
var resourceyescount = 0;
try {
var gridCtx = formContext._gridControl;
var grid = gridCtx.getGrid();
var allRows = grid.getRows();
var duplicatesFound = 0;
//loop through rows and get the attribute collection
allRows.forEach(function (row, rowIndex) {
var thisRow = row.getData().entity;
var thisRowId = thisRow.getId();
var thisResource = "";
var thisResourceName = "";
var thisResourceID = "";
console.log("this row id=" + thisRowId);
var thisAttributeColl = row.getData().entity.attributes;
thisAttributeColl.forEach(function (thisAttribute, attrIndex) {
var msg = "";
if (thisAttribute.getName() == "new_resource") {
thisResource = thisAttribute.getValue();
thisResourceID = thisResource[0].id;
thisResourceName = thisResource[0].name;
console.log("this resource name=" + thisResourceName)
}
});
var allRows2 = formContext.getGrid().getRows();
//loop through rows and get the attribute collection
allRows2.forEach(function (row, rowIndex) {
var thatRow = row.getData().entity;
var thatRowId = thatRow.getId();
var thatAttributeColl = row.getData().entity.attributes;
var thatResource = "";
var thatResourceName = "";
var thatResourceID = "";
thatAttributeColl.forEach(function (thatAttribute, attrIndex) {
if (thatAttribute.getName() == "new_resource") {
thatResource = thatAttribute.getValue();
thatResourceID = thatResource[0].id;
thatResourceName = thatResource[0].name;
if (thatResourceID == thisResourceID && thatRowId != thisRowId) {
duplicatesFound++;
var msg = "Duplicate resource " + thatResource;
console.log("duplicates found= " + duplicatesFound);
}
}
});
});
});
if (duplicatesFound > 0) {
console.log("duplicate found");
Xrm.Page.getAttribute("new_showduplicateerror").setValue(true);
Xrm.Page.getControl("new_showduplicateerror").setVisible(true);
Xrm.Page.getControl("new_showduplicateerror").setNotification("A duplicate resource was found. Please remove this before saving.");
} else {
Xrm.Page.getAttribute("new_showduplicateerror").setValue(false);
Xrm.Page.getControl("new_showduplicateerror").setVisible(false);
Xrm.Page.getControl("new_showduplicateerror").clearNotification();
}
} catch (err) {
console.log('Error occurred :' + err)
}
}
Here is a separate web resource that triggers the function:
function TriggerSalesQDResourceCount(executionContext){
var formContext = executionContext.getFormContext();
formContext.getControl("s_qd").addOnLoad(GetTotalResourceCount);
}
Any ideas how I can fix this? Is this a known issue with the new D365 wave 1 update?
Thanks!
This is the problem with unsupported (undocumented) code usage, which will break in future updates.
Unsupported:
var gridCtx = formContext._gridControl;
You have to switch to these supported methods.
function doSomething(executionContext) {
var formContext = executionContext.getFormContext(); // get the form Context
var gridContext = formContext.getControl("Contacts"); // get the grid context
// Perform operations on the subgrid
var grid = gridContext.getGrid();
}
References:
Client API grid context
Grid (Client API reference)
Related
I'm binding data to 3 dropdowns by calling a method from another file of javascript. The data source of dropdown loading from IndexedDB.
Data binding JS,
function bindStateData(){
getMstStates("#state");
getMstStates("#drstate");
getMstStates("#cstate");
}
Database manager js,
function getMstStates(state) {
var request = indexedDB.open('AppDatabase', '3')
request.onsuccess = function (e) {
var dbInstance = e.target.result;
let transaction = dbInstance.transaction("MstStates", "readonly");
const statesDetailsStore = transaction.objectStore("MstStates");
stateData = statesDetailsStore.getAll();
stateData.onsuccess = function () {
var MstStatesMap = new Object();
var len = stateData.result.length,
i;
for (i = 0; i < len; i++) {
MstStatesMap[i] = {};
MstStatesMap[i].StateId = stateData.result[i].StateId;
MstStatesMap[i].StateName = stateData.result[i].StateName;
}
callBackOptionItems(MstStatesMap, state);
}
stateData.onerror = function () {
console.log('getMstStates : ' + e);
}
}
request.onerror = function (e) { console.log('getMstStates : ' + e); }
}
function callBackOptionItems(MstOptionMap, objID) {
for (var j in MstOptionMap) {
var k, v
var tem = 0;
for (var i in MstOptionMap[j]) {
if (tem == 0) {
k = MstOptionMap[j][i]
} else {
v = MstOptionMap[j][i];
}
tem++
}
var el = $(objID);
$(el).append('<option value="' + k + '">' + v + '</option>');
}
if (objID == '#select-history') {
$("#select-history").append('<option value="4">Other</option>');
}
}
When I tried to loading data I got the following error,
Uncaught DOMException: Failed to read the 'result' property from 'IDBRequest': The request has not finished.
at IDBRequest.stateData.onsuccess
The same code logic was written in WebSQL, it was running properly, but unfortunately from iOS 13 version websql support has been revoked.
I have resolved this issue. The main culprit line is,
var len = stateData.result.length;
The correct code is as follows,
var _request = statesDetailsStore.getAll();
_request.onsuccess = function (event) {
var MstStatesMap = new Object();
var stateData = event.target.result;
}
I want to restrict the user from adding more product to sell if the order is tag as booked order
I want to show popup error message when it is booked order and the user still click the product
here is my code
odoo.define('tw_pos_inherit_model.attemptInherit', function (require) {
"use strict";
var POSInheritmodel = require('point_of_sale.models');
var ajax = require('web.ajax');
var BarcodeParser = require('barcodes.BarcodeParser');
var PosDB = require('point_of_sale.DB');
var devices = require('point_of_sale.devices');
var concurrency = require('web.concurrency');
var config = require('web.config');
var core = require('web.core');
var field_utils = require('web.field_utils');
var rpc = require('web.rpc');
var session = require('web.session');
var time = require('web.time');
var utils = require('web.utils');
var gui = require('point_of_sale.gui');
var orderline_id = 1;
var QWeb = core.qweb;
var _t = core._t;
var Mutex = concurrency.Mutex;
var round_di = utils.round_decimals;
var round_pr = utils.round_precision;
var _super_order = POSInheritmodel.Order.prototype;
POSInheritmodel.Order = POSInheritmodel.Order.extend({
add_product: function(product, options){
var can_add = true;
var changes = this.pos.get_order();
var self = this;
try{
if(changes.selected_orderline.order.quotation_ref.book_order){
can_add= false;
}
}catch(err){}
if (can_add){
if(this._printed){
this.destroy();
return this.pos.get_order().add_product(product, options);
}
this.assert_editable();
options = options || {};
var attr = JSON.parse(JSON.stringify(product));
attr.pos = this.pos;
attr.order = this;
var line = new POSInheritmodel.Orderline({}, {pos: this.pos, order: this, product: product});
if(options.quantity !== undefined){
line.set_quantity(options.quantity);
}
if(options.price !== undefined){
line.set_unit_price(options.price);
}
//To substract from the unit price the included taxes mapped by the fiscal position
this.fix_tax_included_price(line);
if(options.discount !== undefined){
line.set_discount(options.discount);
}
if(options.discount_percentage !== undefined){
line.set_if_discount_percentage(options.discount_percentage);
}
if(options.discount_amount !== undefined){
line.set_if_discount_amount(options.discount_amount);
}
if(options.extras !== undefined){
for (var prop in options.extras) {
line[prop] = options.extras[prop];
}
}
var to_merge_orderline;
for (var i = 0; i < this.orderlines.length; i++) {
if(this.orderlines.at(i).can_be_merged_with(line) && options.merge !== false){
to_merge_orderline = this.orderlines.at(i);
}
}
if (to_merge_orderline){
to_merge_orderline.merge(line);
} else {
this.orderlines.add(line);
}
this.select_orderline(this.get_last_orderline());
if(line.has_product_lot){
this.display_lot_popup();
}
}else{
self.gui.show_popup('error',{
title :_t('Modification Resctricted'),
body :_t('Booked Order cannot be modified'),
});
}
},
});
});
but im getting an error
Uncaught TypeError: Cannot read property 'show_popup' of undefined
http://localhost:8071/web/content/554-cbfea6c/point_of_sale.assets.js:475
Traceback:
TypeError: Cannot read property 'show_popup' of undefined
at child.add_product (http://localhost:8071/web/content/554-cbfea6c/point_of_sale.assets.js:475:116)
at Class.click_product (http://localhost:8071/web/content/554-cbfea6c/point_of_sale.assets.js:326:257)
at Object.click_product_action (http://localhost:8071/web/content/554-cbfea6c/point_of_sale.assets.js:325:951)
at HTMLElement.click_product_handler (http://localhost:8071/web/content/554-cbfea6c/point_of_sale.assets.js:320:1738)
im sorry im really confuse do i still need to initialized the this.gui first?
even though i have var gui = require('point_of_sale.gui'); initialized already
when i log the this.gui to my console the output is undefined
You can access gui via posModel.
self.pos.gui.show_popup('error',{
title :_t('Modification Resctricted'),
body :_t('Booked Order cannot be modified'),
});
You can check an example at connect_to_proxy
I am working on my hello world project. I have two pages let's call them "configuration" and "add configuration" *.html. Each one has its own controller like this:
angular.module('MissionControlApp').controller('ConfigController', ConfigController);
angular.module('MissionControlApp').controller('AddConfigController', AddConfigController);
Now, each controller has some properties that very much overlap:
function ConfigController($routeParams, ConfigFactory, $window){
var vm = this;
vm.status;
vm.projectId = $routeParams.projectId;
vm.selectedProject;
vm.configurations;
vm.selectedConfig;
vm.selectedRecords;
vm.filteredConfig;
vm.newFile;
vm.fileWarningMsg = '';
vm.addFile = function(){
var filePath = vm.newFile;
var encodedUri = encodeURIComponent(filePath);
vm.fileWarningMsg='';
ConfigFactory
.getByEncodedUri(encodedUri).then(function(response){
var configFound = response.data;
var configNames = '';
var configMatched = false;
if(response.status === 200 && configFound.length > 0){
//find an exact match from text search result
for(var i = 0; i < configFound.length; i++) {
var config = configFound[i];
for(var j=0; j<config.files.length; j++){
var file = config.files[j];
if(file.centralPath.toLowerCase() === filePath.toLowerCase()){
configMatched = true;
configNames += ' [' + config.name + '] ';
break;
}
}
}
}
if(configMatched){
vm.fileWarningMsg = 'Warning! File already exists in other configurations.\n' + configNames;
} else if(filePath.length > 0 && filePath.includes('.rvt')){
var file1 = { centralPath: filePath };
vm.selectedConfig.files.push(file1);
vm.newFile = '';
} else{
vm.fileWarningMsg = 'Warning! Please enter a valid file.';
}
}, function(error){
vm.status = 'Unable to get configuration data: ' + error.message;
});
};
My AddConfigController also wants to have the same functionality for addFile() so I just copy pasted the same code, but coming from C# i am sure i can do some class inheritance here, and just inherit from ConfigController and extend...right?
If this is super noob question. then apologies. js is a bit of a mystery to me.
function AddConfigController($routeParams, ConfigFactory, $window){
var vm = this;
vm.status;
vm.projectId = $routeParams.projectId;
vm.selectedProject = {};
vm.newConfig = {};
vm.newFile;
vm.fileWarningMsg = '';
vm.addFile = function(){
var filePath = vm.newFile;
var encodedUri = encodeURIComponent(filePath);
vm.fileWarningMsg='';
ConfigFactory
.getByEncodedUri(encodedUri).then(function(response){
var configFound = response.data;
var configNames = '';
var configMatched = false;
if(response.status === 200 && configFound.length > 0){
//find an exact match from text search result
for(var i = 0; i < configFound.length; i++) {
var config = configFound[i];
for(var j=0; j<config.files.length; j++){
var file = config.files[j];
if(file.centralPath.toLowerCase() === filePath.toLowerCase()){
configMatched = true;
configNames += ' [' + config.name + '] ';
break;
}
}
}
}
if(configMatched){
vm.fileWarningMsg = 'Warning! File already exists in other configurations.\n' + configNames;
} else if(filePath.length > 0 && filePath.includes('.rvt')){
var file1 = { centralPath: filePath };
vm.selectedConfig.files.push(file1);
vm.newFile = '';
} else{
vm.fileWarningMsg = 'Warning! Please enter a valid file.';
}
}, function(error){
vm.status = 'Unable to get configuration data: ' + error.message;
});
};
Since you asked about inheritance and you appear to be using ECMAScript 5, let me suggest taking a look at Object.create(). Specifically, the classical inheritance example.
That said, in AngularJS, a better solution would be to create a Service that manages files or configurations and put the addFile function in there. That way, both controllers could inject the service and call the same function when it is time to add a file. Likewise, other services and controllers that may need access to this functionality could inject it as well.
Hello you wonderful people, I am trying to build JavaScript file to extract information from Wikipedia based on search value in the input field and then display the results with the title like link so the user can click the link and read about it. So far I am getting the requested information in(JSON)format from Mediawiki(Wikipedia) but I can't get it to display on the page. I think I have an error code after the JavaScript array.
I'm new at JavaScript any help, or hint will be appreciated.
Sorry my script is messy but I am experimenting a lot with it.
Thanks.
var httpRequest = false ;
var wikiReport;
function getRequestObject() {
try {
httpRequest = new XMLHttpRequest();
} catch (requestError) {
return false;
}
return httpRequest;
}
function getWiki(evt) {
if (evt.preventDefault) {
evt.preventDefault();
} else {
evt.returnValue = false;
}
var search = document.getElementsByTagName("input")[0].value;//("search").value;
if (!httpRequest) {
httpRequest = getRequestObject();
}
httpRequest.abort();
httpRequest.open("GET", "https://en.wikipedia.org/w/api.php?action=query&format=json&gsrlimit=3&generator=search&origin=*&gsrsearch=" + search , true);//("get", "StockCheck.php?t=" + entry, true);
//httpRequest.send();
httpRequest.send();
httpRequest.onreadystatechange = displayData;
}
function displayData() {
if(httpRequest.readyState === 4 && httpRequest.status === 200) {
wikiReport = JSON.parse(httpRequest.responseText);//for sunchronus request
//wikiReport = httpRequest.responseText;//for asynchronus request and response
//var wikiReport = httpRequest.responseXML;//processing XML data
var info = wikiReport.query;
var articleWiki = document.getElementsByTagName("article")[0];//creating the div array for displaying the results
var articleW = document.getElementById("results")[0];
for(var i = 0; i < info.length; i++)
{
var testDiv = document.createElement("results");
testDiv.append("<p><a href='https://en.wikipedia.org/?curid=" + query.pages[i].pageid + "' target='_blank'>" + query.info[i].title + "</a></p>");
testDiv.appendChild("<p><a href='https://en.wikipedia.org/?curid=" + query.info[i].pageid + "' target='_blank'>" + query.info[i].title + "</a></p>");
var newDiv = document.createElement("div");
var head = document.createDocumentFragment();
var newP1 = document.createElement("p");
var newP2 = document.createElement("p");
var newA = document.createElement("a");
head.appendChild(newP1);
newA.innerHTML = info[i].pages;
newA.setAttribute("href", info[i].pages);
newP1.appendChild(newA);
newP1.className = "head";
newP2.innerHTML = info[i].title;
newP2.className = "url";
newDiv.appendChild(head);
newDiv.appendChild(newP2);
articleWiki.appendChild(newDiv);
}
}
}
//
function createEventListener(){
var form = document.getElementsByTagName("form")[0];
if (form.addEventListener) {
form.addEventListener("submit", getWiki, false);
} else if (form.attachEvent) {
form.attachEvent("onsubmit", getWiki);
}
}
//createEventListener when the page load
if (window.addEventListener) {
window.addEventListener("load", createEventListener, false);
} else if (window.attachEvent) {
window.attachEvent("onload", createEventListener);
}
Mediawiki api link
https://en.wikipedia.org/w/api.php?action=query&format=json&gsrlimit=3&generator=search&origin=*&gsrsearch=
You are wrong some points.
1)
var articleW = document.getElementById("results")[0];
This is wrong. This will return a element is a reference to an Element object, or null if an element with the specified ID is not in the document. Doc is here (https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById)
The correct answer should be :
var articleW = document.getElementById("results");
2)
var info = wikiReport.query;
for(var i = 0; i < info.length; i++) {}
The info is object . it is not array , you can't for-loop to get child value.
wikiReport.query is not correct wiki data. The correct data should be wikiReport.query.pages. And use for-in-loop to get child element
The correct answer:
var pages = wikiReport.query.pages
for(var key in pages) {
var el = pages[key];
}
3) This is incorrect too
testDiv.appendChild("<p><a href='https://en.wikipedia.org/?curid=" + query.info[i].pageid + "' target='_blank'>" + query.info[i].title + "</a></p>");
The Node.appendChild() method adds a node to the end of the list of children of a specified parent node. You are using the method to adds a string . This will cause error. Change it to node element or use append method instead
I have created a sample test.You can check it at this link below https://codepen.io/anon/pen/XRjOQQ?editors=1011
Alright, this one's got me seriously stumped, after trying things out for hours with the block of javascript below I'm still getting the same error in IE's javascript debugger.
The error I'm getting is SCRIPT5007: Unable to get value of the property 'get_id': object is null or undefined.
And below is my code:
AS.SP.ClientActions.ClientProgramEdit_Status = new AS.SP.ClientActions.ButtonStatus();
AS.SP.ClientActions.Can_ClientProgramEdit = function (groupID) {
var OnError = function (sender, args) {
AS.SP.ClientActions.ClientProgramEdit_Status.enabled = false;
RefreshCommandUI();
};
var items = AS.SP.ClientActions.GetSelectedItems();
var count = CountDictionary(items);
if (count === 1) {
var itemID = items[0].id;
if (AS.SP.ClientActions.ClientProgramEdit_Status.itemID != itemID) {
AS.SP.ClientActions.ClientProgramEdit_Status.itemID = itemID;
AS.SP.ClientActions.ClientProgramEdit_Status.enabled = false;
AS.SP.ClientActions.GetUrl(function (rootUrl) {
var fragments = AS.SP.Navigation.ParseUri(rootUrl);
var ctx = new SP.ClientContext(fragments.path);
var web = ctx.get_web();
var props = web.get_allProperties();
ctx.load(web);
ctx.load(props);
ctx.executeQueryAsync(function () {
var listId = 'Client Programs';
var sdlist = web.get_lists().getByTitle(listId);
var locationID = props.get_item('WL_ITEM_ID');
var query = new SP.CamlQuery();
query.set_viewXml('<View><Query><Where><And><Eq><FieldRef Name="len_cp_Location" /><Value Type="Text">' + locationID + '</Value></Eq><Eq><FieldRef Name="len_cp_Client_Status" /><Value Type="Text">Inactive</Value></Eq></And></Where></Query><ViewFields><FieldRef Name="Title" /></ViewFields></View>');
var items = sdlist.getItems(query);
ctx.load(items);
ctx.executeQueryAsync(function () {
var item = items.itemAt(0);
var itemID = item.get_id();
if (itemID == "WL_ITEM_ID") {
AS.SP.ClientActions.ClientProgramEdit_Status.enabled = true;
RefreshCommandUI();
}
}, OnError);
}, OnError);
});
}
}
return AS.SP.ClientActions.ClientProgramEdit_Status.enabled;
}
My theory is that I've done something wrong with my CAML query but at this point I really don't know, any help with this would be greatly appreciated, thanks!
You are using the items variable twice, once on line 9:
var items = AS.SP.ClientActions.GetSelectedItems();
And again inside GetUrl:
var items = sdlist.getItems(query);
There is a name conflict in your execureQueryAsync closure. I would begin by fixing this issue. Which items collection do you want to reference? Do you mean to load the original items variable:
ctx.load(items);
var items = sdlist.getItems(query);