Get a first look at what's coming. The Developer Passport Australia Release Preview kicks off March 12. Dive in! 

How to check csv column header name in client controller script of the widget?

Virendra K
Kilo Sage

Hi All,

I have requirement to check the attached csv file's 1st column header using client controller script in the widget.

I am trying to use below code and changed the name of the header name of the csv file but its not working.

 

$scope.header = angular.element('#header').val();
        if ($scope.header != 'CI Name' ) {
            alert('VIR ci name passed ');
            $scope.title ="Invalid file format: ";
            $scope.message = "Ensure the 'CI Name' column is the first column in the file.";
            return false;
        }
 
I am not an expert in portal (html/angular script). Please help me to achieve this.
 
Thanks in advance.
 
Regards,
Virendra

  

1 ACCEPTED SOLUTION

@Virendra K 

this is a sample working code for your validation

I am checking if first column is Name

you can enhance it further based on your requirement.

HTML:

<label for="csvUpload">Upload CSV file:</label>
<input type="file" id="csvUpload" accept=".csv" onchange="angular.element(this).scope().validateCSV(event)" />

<div ng-if="error" style="color: red; margin-top: 10px;">
  {{ error }}
</div>

Client Controller:

function($scope) {
  $scope.error = "";

  $scope.validateCSV = function(event) {
    let file = event.target.files[0];
    $scope.error = "";

    if (!file) return;

    let reader = new FileReader();

    reader.onload = function(e) {
      let contents = e.target.result;
      let lines = contents.split(/\r\n|\n/);

      if (lines.length === 0) {
        $scope.$apply(() => $scope.error = "CSV file is empty.");
        return;
      }

      // Get first line (header)
      let headers = lines[0].split(',');

      if (headers[0].trim() !== "Name") {
        $scope.$apply(() => $scope.error = "First column header must be 'Name'.");
        return;
      }

      $scope.$apply(() => $scope.error = "CSV file is valid.");
    };

    reader.readAsText(file);
  };
}

Server:

(function() {
  data.error = "";

  // Server script doesn't need to process file here, validation done client-side
})();

Output:

csv validate 1st column widget.gif

I hope you will mark my response as correct as I shared a working solution which you can enhance further based on your developer skills and customer requirements

Regards,
Ankur
Certified Technical Architect  ||  10x ServiceNow MVP  ||  ServiceNow Community Leader

View solution in original post

11 REPLIES 11

Here is a snippet html template and controller you can start from but getting it to your specs might require a little bit of understanding of angular and the oob widgets. You can put this in a catalog item as a widget variable and test it out.

 

The logic you are talking of could be put in the setAttachments callback function passed to the nowAttachmentHandler.

<!-- from oob sc cat item widget -->
<div ng-if="true" class="wrapper-md row no-margin" role="region" data-label="Attachments"
    aria-label="${Attachments}">
    <div
        ng-class="{'flex-center attachment-height': c.isNative == 'true', 'flex-start': c.isNative != 'true'}">
        <div ng-if="!submitting && !submitted" style="font-weight:normal;cursor:default;margin-bottom:2rem;">
            <sp-attachment-button ng-if="::!showDragAndDrop()" modal="true" supported-extensions="exe, bat, sh"
                required="{{data.mandatory_attachment}}"></sp-attachment-button>
            <sp-attachment-button ng-if="::showDragAndDrop()" modal="true"
                required="{{data.mandatory_attachment}}"
                ng-class="{'hidden-xs': false, 'hidden-sm': true, 'hidden-md': true, 'hidden-lg': true}"></sp-attachment-button>
            <span class="fa fa-asterisk mandatory" ng-if="data.mandatory_attachment"
                ng-class="{'mandatory-filled': data.mandatory_attachment && (data.attachment_submitted || attachments.length > 0)}"
                style="vertical-align:super" aria-hidden="true"></span>
            <span ng-class="{'attachment-text' : options.native_mobile == 'true'}" aria-hidden="true">${Add
                attachments}</span>
        </div>
    </div>
<div ng-if="::showDragAndDrop()" class="panel panel-{{options.color}} b drag-and-drop-area"
        ng-class="{'hidden-xs': true}" aria-hidden="true">
        <sp-attachment-picker on-file-pick="dropFiles($files)"></sp-attachment-picker>
    </div>
    <span ng-if="attachmentUploadInProgress">${Uploading attachments}
        <div class="sp-loading-indicator la-sm" style="color:black;display:inline">
            <div></div>
            <div></div>
            <div></div>
        </div>
    </span>
    <now-attachments-list template="sp_attachment_single_line"></now-attachments-list>
</div>
api.controller = function ($scope, nowAttachmentHandler, spUtil, spAttachmentUpload, $timeout, cabrillo, spModal) {
	var c = this;
	c.isNative = cabrillo.isNative()
	$scope.table = $scope.page.g_form.recordTableName;
	$scope.guid = $scope.$parent.c.getAttachmentGuid();
	$scope.data.maxAttachmentSize = 24;
	var ah = $scope.attachmentHandler = new nowAttachmentHandler(setAttachments, appendError);
	ah.setParams($scope.table, $scope.guid, 1024 * 1024 * $scope.data.maxAttachmentSize);
	$scope.showDragAndDrop = function () {
		if (true)
			return true;
		else
			return false;
	}

	function setAttachments(attachments, action) {
		if (!angular.equals($scope.attachments, attachments))
			$scope.attachments = attachments;
		if (action === "added") {
			
			console.log(attachments[0]);
		}
		if (action === "renamed") {
			// attachment renamed logic
		}
		if (action === "deleted") {
			// attachment deleted logic
		}
		spUtil.get($scope, {
			action: "from_attachment"
		});

	}
	function appendError(error) {
		spUtil.addErrorMessage(error.msg + error.fileName);
	}

	$scope.dropFiles = function (files) {
		if (files && files.length > 0) {
			$scope.attachmentUploadInProgress = true;
			$scope.totalFilesBeingUploaded++;
			spAttachmentUpload.uploadAttachments($scope.attachmentHandler, files);
		}
		$timeout(function () {
			if ($scope.attachmentUploadInProgress != false)
				spUtil.addInfoMessage($scope.data.attachmentUploadProgressMsg);
		}, 2000);
		$scope.$on('attachment.upload.idle', function () {
			$scope.attachmentUploadInProgress = false;
			$scope.totalFilesBeingUploaded = 0;
		});
	};
	$scope.confirmDeleteAttachment = function (attachment) {
		if (c.isNative) {
			if (confirm("delete attachment?")) {
				$scope.data.attachment_action_in_progress = true;
				$scope.attachmentHandler.deleteAttachment(attachment);
			}
		} else {
			spModal.confirm("delete attachment?").then(function () {
				$scope.data.attachment_action_in_progress = true;
				$scope.attachmentHandler.deleteAttachment(attachment);
			});
		}
	}
};

 

PrajaktaG308421
Mega Guru

Hello @Virendra K ,

I am also not much expert in portal ,I found something related which you can try once 

1.angular.element('#header').val() does not read inside a file
2.Browsers do NOT expose CSV content via <input type="file">

3.You must read the file using JavaScript FileReader first.


1.In widget HTML
<input type="file" id="csvFile" accept=".csv" />

2.In client controller use FileReader to read the CSV
$scope.validateCSV = function() {
var fileInput = document.getElementById('csvFile');
var file = fileInput.files[0];

if (!file) {
alert("Please upload a file first.");
return false;
}

var reader = new FileReader();

reader.onload = function(e) {
var text = e.target.result;

// Split first line (header row)
var firstLine = text.split('\n')[0].trim();

// Read the first column header
var firstColumnHeader = firstLine.split(',')[0].trim().replace(/"/g, '');

console.log("First Column Header:", firstColumnHeader);

if (firstColumnHeader !== 'CI Name') {
$scope.title = "Invalid file format";
$scope.message = "Ensure the 'CI Name' column is the first column in the CSV.";
alert($scope.message);
$scope.$apply();
return false;
} else {
alert("CSV is valid!");
}
};

reader.readAsText(file);
};

3.Add a button to trigger the validation
<button class="btn btn-primary" ng-click="validateCSV()">Validate CSV</button>