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.
Related
So I already looked at all the articles that I could find here, yet I still couldn't solve the problem. My question is how do I make Google App Scripts ask for permission to view certain files. Here's the problem in Google App Scripts:
Script:
var NamesToDelete = [""];
function moveFiles(sourceFileId, targetFolderId) {
var file = DriveApp.getFileById(sourceFileId);
var folder = DriveApp.getFolderById(targetFolderId);
file.moveTo(folder);
}
function createFolder(folderName){
var parentFolder = DriveApp.getRootFolder();
var subFolders = parentFolder.getFolders();
var doesntExists = true;
var newFolder = '';
// Check if folder already exists.
while(subFolders.hasNext()){
var folder = subFolders.next();
//If the name exists return the id of the folder
if(folder.getName() === folderName){
doesntExists = false;
newFolder = folder;
return newFolder.getId();
};
};
//If the name doesn't exists, then create a new folder
if(doesntExists == true){
//If the file doesn't exists
newFolder = parentFolder.createFolder(folderName);
return newFolder.getId();
};
};
function start(user){
var body = "Hello " + user + ",<br> Your google drive cleanup has been successfully initiated. <br> Please go to your drive and click the file named 'Delete Me.' Select everything inside (shift+select) and right click it. In the options that come up, click 'Remove.' <br> Thank you, <br> SS Tools"
body = body + "<br> Words you chose: <br>";
for (var i = 0; i<NamesToDelete.length; i++) {
body = body + NamesToDelete[i] + "<br>";
}
var NEW_FOLDER_NAME = "DELETE ME";
var myFolderID = createFolder(NEW_FOLDER_NAME);
var tutorialPicture = UrlFetchApp
.fetch("https://i.gyazo.com/f8716f9d9b0539506a78fba52e12788b.png")
.getBlob()
.setName("How to Delete");
Logger.log(myFolderID);
listFolders(myFolderID)
MailApp.sendEmail({
to: user,
subject: "SS Tools: Drive Cleanup Successfully Initiated",
htmlBody: body,
inlineImages:
{
Tutorial: tutorialPicture,
}
});
};
function FirstWord(word) {
var wordLength = word.length
var firstWord = ""
for (var i = 0; i < wordLength; i++) {
var c = word[i]
if (c == " ") {
break;
}
else if(c >= '0' && c <= '9') {
continue;
}
firstWord = firstWord + word[i]
}
return firstWord
}
function checkIfDeleteAB(One, Two) {
var theFirstWord = FirstWord(One)
if (theFirstWord == Two || theFirstWord == "") {
return true
}
return false
}
function listFolders(parentID, folder) {
folder = folder || DriveApp.getRootFolder();
var name = folder.getName();
var files = folder.getFiles();
while ( files.hasNext() ) {
var nextFile = files.next();
var nextName = nextFile.getName();
var arrayLength = NamesToDelete.length
for (var i = 0; i < arrayLength; i++) {
if (checkIfDeleteAB(nextName, NamesToDelete[i])) {
Logger.log(name + " :: " + nextName);
//nextFile.setTrashed(true);
moveFiles(nextFile.getId(), parentID);
break;
}
}
}
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
listFolders(parentID, subfolders.next());
}
}
function GetResponsesArray(form) {
var response = form.response;
var user = response.getRespondentEmail();
var item = response.getItemResponses();
var array = item[0].getResponse();
var word = "";
var c = 0;
var done = false;
Logger.log(array)
for (var i = 0; i<array.length; i++){
if(array[i] == " "){
c = 0;
NamesToDelete.push(word);
Logger.log(word)
word = "";
done = true;
}else{
word += array[i];
Logger.log("Shaping word :: " + word)
c++;
done = false;
}
}
if (done == false){
NamesToDelete.push(word);
}
Logger.log(user)
start(user);
}
If you can find the answer to my question I would be grateful!
Google gives the following explanation for the Access denied: DriveApp exception:
Administrators of G Suite domains have the ability to disable the Drive SDK for their domain, which prevents their users from installing and using Google Drive apps. This setting also prevents the users from being able to use Apps Script add-ons that use the Drive service or Advanced Drive Service (even if the script was authorized prior to the admin disabling Drive SDK).
In other words, it seems like you are not the admin of your domain and the admin had disabled the usage of Drive SDK for you / for the whole doman.
You need to contact the admin and ask him to change permissions.
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)
i´m desperately finding a solution for my issue. I need to place a huge amount of inline graphics in InDesign with this script, but for some reason it doesn't work. I have a very poor knowledge of Javascript and my time is running out so i cannot spend much time studying JS. I'm working in InDesign CC2014 on an iMac with Yosemite.
The following error message pops-up:
error snap:
I'll be so glad if someone give me a light on this.
main();
function main() {
var name, f, file, text,
arr = [];
if(app.documents.length != 0) {
var doc = app.activeDocument;
var folder = Folder.selectDialog("Choose a folder with images");
if (folder != null) {
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
app.findGrepPreferences.findWhat = "#.+?#";
f = doc.findGrep(true);
for (i = 0; i < f.length; i++) {
name = f[i].contents.replace(/#/g, "");
file = new File(folder.fsName + "/" + name);
if (file.exists) {
f[i].contents = "";
var rect = f[i].insertionPoints[0].rectangles.add({geometricBounds:[0,0, 60, 40.667 ]} );
rect.place ( file );
rect.fit ( FitOptions.FRAME_TO_CONTENT);
}
else {
arr.push("File doesn't exist '" + name + "'");
}
}
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
arr.push("------------------------------------------");
text = arr.join("\r");
writeToFile(text);
}
}
else{
alert("Please open a document and try again.");
}
}
function writeToFile(text) {
var file = new File("~/Desktop/Place inline images.txt");
if (file.exists) {
file.open("e");
file.seek(0, 2);
}
else {
file.open("w");
}
file.write(text + "\r");
file.close();
}
Problem is - probably - cause script is editing found contents and refering to it in the next lines of code.
I suggest to use backward looping and move f[i].contents = "" to the line after.
Something like:
main();
function main() {
var name, f, cF, file, text,
arr = [];
if(app.documents.length != 0) {
var doc = app.activeDocument;
var folder = Folder.selectDialog("Choose a folder with images");
if (folder != null) {
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
app.findGrepPreferences.findWhat = "#.+?#";
f = doc.findGrep(true);
while(cF = f.pop()) {
name = cF.contents.replace(/#/g, "");
file = new File(folder.fsName + "/" + name);
if (file.exists) {
var rect = cF.insertionPoints[0].rectangles.add({geometricBounds:[0,0, 60, 40.667 ]} );
rect.place ( file );
rect.fit ( FitOptions.FRAME_TO_CONTENT);
cF.contents = "";
}
else {
arr.push("File doesn't exist '" + name + "'");
}
}
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
arr.push("------------------------------------------");
text = arr.join("\r");
writeToFile(text);
}
}
else{
alert("Please open a document and try again.");
}
}
function writeToFile(text) {
var file = new File("~/Desktop/Place inline images.txt");
if (file.exists) {
file.open("e");
file.seek(0, 2);
}
else {
file.open("w");
}
file.write(text + "\r");
file.close();
}
this is the html code:
<li ng-repeat="data in spreadGroupData" ng-click="channelList(data.campaigns,data.name)">{{data.name}}</li>`
this is the code i write in the services.js:
services.getChannelName = function($scope,channelidList){
httpurl = "api/account/"+nowuID+"/channel/channellist?id=" + channelidList;
$http.get(httpurl).success(function(data){
if(data.length>0){
$scope.spreadGroupData = [];
for(var i in data){
var group = {};
group.campaigns = data[i].id;
group.name = data[i].name;
$scope.spreadGroupData.push(group);
}
}
});
};
there are data in $scope.spreadGroupData,why couldn't show in the view page?
Now I know I shouldn't use $scope in the service,but the param 'channelidList' I get it from another service method. How to rewrite this all?
services.getListData = function(scope,flag){
var reportList = "quality_report",merger = true;
if(typeof flag!='undefined' && flag == 1){
reportList = "fakequality_report";
merger = false;
}
var cids = scope.spreadUrls,dateArr=scope.date.split(" - "),startDate = "",endDate = "",channelids = "";
if(dateArr.length==1){
startDate = endDate = dateArr[0];
}else{
startDate = dateArr[0];
endDate = dateArr[1];
}
if(cids!=null){
if(cids!='All'){
channelids = "&channelid="+cids.join(",");
}
if(scope.selecteds != -1 && typeof(scope.selecteds) != "undefined"){
httpurl = "api/app/"+scope.selecteds+"/report/"+reportList+"?startdate="+startDate+"&enddate="+endDate+channelids;
$http.get(httpurl).success(function(data,status){
scope.tabTitle = data.name;
var tableList = services.colToRow(data.val),cidlen = cids.length;
scope.tabTotal = services.dataToTotal(data.val,cidlen);
var key = data.key,tabname = [],zero = [],tabListInfo = [],allnames = scope.spreadNames;
for(var i=0;i<scope.tabTotal.length;i++){
zero[i] = 0;
}
for(i=0;i<cidlen;i++){
var idx = $.inArray(allnames[i],key);
tabListInfo[i] = new Array();
if(idx>-1){
tabListInfo[i] = tableList[idx];
}else{
tabListInfo[i] = zero;
}
if(merger){
var temp = [];
for(var j=0;j<tabListInfo[i].length;j++){
temp[j] = tabListInfo[i][j];
}
temp.unshift(scope.spreadNames[i]);
tabListInfo[i] = temp;
}
}
var channelIdList = [];
if(key.length>0){
var n = 0;
for(var i in scope.spreadData){
for(var j in key){
if(key[j] == scope.spreadData[i].name){
n++;
channelIdList.push(scope.spreadData[i].channel);
if(n>20) break;
}
}
}
}
services.getChannelName(scope,channelIdList.join(","));
scope.tabname = scope.spreadNames;
if(merger){
var tabListObj = [];
if(reportList == "quality_report"){
for(var i = 0; i <tabListInfo.length; i++){
tabListObj.push({
"name" : tabListInfo[i][0],
"hitNum" : tabListInfo[i][1],
"reSchedulNum" : tabListInfo[i][2],
"activeDevice" : tabListInfo[i][3],
"activeRate" : tabListInfo[i][4],
"payment" : tabListInfo[i][5],
"spdID" : cids[i]
});
}
}
scope.tabListInfo = tabListObj;
}else{
if(reportList == "fakequality_report"){
var tabListObj = [];
for(var i = 0; i <tabListInfo.length; i++){
tabListObj.push({
"name" : scope.tabname[i],
"reSchedulNum" : tabListInfo[i][0],
"hitNum" : tabListInfo[i][1],
"errHitNum" : tabListInfo[i][2],
"errHitRate" : tabListInfo[i][3],
"activeDevice" : tabListInfo[i][4],
"errActDevice" : tabListInfo[i][5],
"errActRate" : tabListInfo[i][6],
"spdID" : cids[i]
});
}
scope.tabListInfo = tabListObj;
}else{
scope.tabListInfo = tabListInfo;
}
}
scope.spreadIDs = cids;
}).error(function(data){
services.loginTimeout(data);
});
}
}
};
You should never pass $scope object to service, service should always have a reusable method which will exposed. I'd suggest you service method should return promise to the controller caller method, and caller method will implement the binding logic inside controller promise success method.
Service Method
services.getChannelName = function(channelidList) {
httpurl = "api/account/" + nowuID + "/channel/channellist?id=" + channelidList;
return $http.get(httpurl).success(function(data) {
return data;
}).error(function(err) {
return err;
});
};
Controller Method
$scope.getChannelName = function() {
$scope.spreadGroupData = [];
service.getChannelName(channelidList).then(function(data) {
if (data.length > 0) {
for (var i in data) {
var group = {};
group.campaigns = data[i].id;
group.name = data[i].name;
$scope.spreadGroupData.push(group);
}
}
}, function(err) {
console.log("Error" + err);
})
}
Update
Whole idea about the code like below. Need to maintain proper code stack resolve.
First service method will return promise, on resolved of it you need to do change in some scope variables, then you will call second service method which has promise, on resolved of it you need to update scope.
Code
services.getListData(flag).then(function(data) { //you may need to pass multiple parameter to this
//then do scope operation
service.getChannelName(channelidList).then(function(res) {
if (res.length > 0) {
for (var i in data) {
var group = {};
group.campaigns = data[i].id;
group.name = data[i].name;
$scope.spreadGroupData.push(group);
}
}
}, function(err) {
console.log("Error" + err);
});
})
I only saw one little thing that might be cause a problem, there is a missing var keyword in front of the httpurl variable and I only add that to below demo.
The view you need to show your data:
<body ng-controller="myController">
Spread Group Data
<br />
------------------------------------------------------------
<li ng-repeat="data in spreadGroupData"
ng-click="channelList(data.campaigns,data.name)">
{{data.name}}
</li>
</body>
I used a mock json provide to simulate your service and call it in a controller directly:
// Prepared a mock json array on the http://beta.json-generator.com and below url returns:
// [{"name":"Item 1","id":1},{"name":"Item 2","id":2},{"name":"Item 3","id":3},{"name":"Item 4","id":4}]
var httpurl = "http://beta.json-generator.com/api/json/get/LoUmNC4";
$http.get(httpurl).success(function(data) {
if (data.length > 0) {
$scope.spreadGroupData = [];
for (var i in data) {
var group = {};
group.campaigns = data[i].id;
group.name = data[i].name;
$scope.spreadGroupData.push(group);
}
}
});
If your service is independent from your controller, then you can pass $scope to your service method. But in this demo I implemented the http call block directly in a main controller. Besides this as #pankajparkar's said do not use the $scope in factories or service unrelated services and take and use response data from that like services. Please check promise and $q in order to handle asynchronous calls.
This is a working demo: Demo
Place $scope.spreadGroupData = []; outside $http call :-
services.getChannelName = function($scope,channelidList){
httpurl = "api/account/"+nowuID+"/channel/channellist?id=" + channelidList;
$scope.spreadGroupData = [];
$http.get(httpurl).success(function(data){
if(data.length>0){
for(var i in data){
var group = {};
group.campaigns = data[i].id;
group.name = data[i].name;
$scope.spreadGroupData.push(group);
}
}
});
};
As seen below I'm trying to get #currentpage to pass client params
Can someone help out thanks.
$(document).ready(function() {
window.addEventListener("load", windowLoaded, false);
function windowLoaded() {
chrome.tabs.getSelected(null, function(tab) {
document.getElementById('currentpage').innerHTML = tab.url;
});
}
var url = $("currentpage");
// yes I relize this is the part not working.
var client = jQuery.param("currentpage");
var page = jQuery.param("currentpage");
var devurl = "http://#/?clientsNumber=" + client + "&pageName=" + page ;
});
This is a method to extract the params from a url
function getUrlParams(url) {
var paramMap = {};
var questionMark = url.indexOf('?');
if (questionMark == -1) {
return paramMap;
}
var parts = url.substring(questionMark + 1).split("&");
for (var i = 0; i < parts.length; i ++) {
var component = parts[i].split("=");
paramMap [decodeURIComponent(component[0])] = decodeURIComponent(component[1]);
}
return paramMap;
}
Here's how to use it in your code
var url = "?c=231171&p=home";
var params = getUrlParams(url);
var devurl = "http://site.com/?c=" + encodeURIComponent(params.c) + "&p=" + encodeURIComponent(params.p) + "&genphase2=true";
// devurl == "http://site.com/?c=231171&p=home&genphase2=true"
See it in action http://jsfiddle.net/mendesjuan/TCpsD/
Here's the code you posted with minimal changes to get it working, it also uses $.param as it's intended, that is to create a query string from a JS object, this works well since my suggested function returns an object from the url
$(document).ready(function() {
// This does not handle arrays because it's not part of the official specs
// PHP and some other server side languages support it but there's no official
// consensus
function getUrlParams(url) {
var paramMap = {};
var questionMark = url.indexOf('?');
if (questionMark == -1) {
return paramMap;
}
var parts = url.substring(questionMark + 1).split("&");
for (var i = 0; i < parts.length; i ++) {
var component = parts[i].split("=");
paramMap [decodeURIComponent(component[0])] = decodeURIComponent(component[1]);
}
return paramMap;
}
// no need for the extra load listener here, jquery.ready already puts
// your code in the onload
chrome.tabs.getSelected(null, function(tab) {
document.getElementById('currentpage').innerHTML = tab.url;
});
var url = $("currentpage");
var paramMap = getUrlParams(url);
// Add the genphase parameter to the param map
paramMap.genphase2 = true;
// Use jQuery.param to create the url to click on
var devurl = "http://site.com/?"+ jQuery.param(paramMap);
$('#mydev').click( function(){
window.open(devurl);
});
});