- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-05-2020 07:05 AM
Hello all,
I am new to Service Portal, creating my very first sample widget today. I have this piece of code below where after clicking "Edit'" button and then clicking on "Save" button, the record should get updated in the incident table. I am able to make changes after clicking "Edit" button, but I am stuck w.r.to updating the changes upon clicking "Save" button. Could you please help me on this.
Serverside:
(function() {
data.incidentdata=[];
var gr=new GlideRecord('incident');
gr.addEncodedQuery('state=2');
gr.query();
while(gr.next())
{
var dataobject={};
dataobject.priority=gr.getDisplayValue('priority');
dataobject.short_description=gr.getDisplayValue('short_description');
dataobject.state=gr.getDisplayValue('priority');
data.incidentdata.push(dataobject);
}
})();
Clientside:
function($scope) {
var c = this;
$scope.display=true;
$scope.saveRecord=function () {
}
}
HTML:
<div>
<p ng-repeat='incident in data.incidentdata'>
<span ng-if='display'>{{incident.short_description}}</span>
<input type='text' ng-model='incident.short_description' ng-if='!display'/>
<button ng-click='display=false'>Edit</button>
<button ng-if='!display' ng-click='saveRecord()'>Save</button>
</p>
</div>
Moreover, I've one more question. How can we use this controller "c" in client script? What is the difference between initializing variables/functions with "$scope" and "c". I did go through a few articles on these, but it will be really helpful if you can explain with an example.
Thank you.
Solved! Go to Solution.
- Labels:
-
Service Portal Development
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-08-2020 11:52 AM
Hi Vinay,
To clear up when to use $scope or c or the difference between $scope or c:
AngularJs inherently has a $scope upon creating/define the ng-app. Each controller has their own scope, just like a function.
A directive (which is what Service Portal's widgets are) has access to scope and can have its own isolated scope. This is what ServiceNow has setup for Service Portal widgets (isolated scopes) so that each widget can have multiple instances on the same page.
But when you want access to the parent scope you need to inject that into the controller.
ie. function($scope) { ....
"c" in the widget is the same as a normal "this" in a function.
The HTML template is the view and it has access to the inherent $scope. So theoretically you can create and assign values in the HTML template.
If something like this is in the HTML template:
<input type="text" ng-model="myvar" ng-init="myvar ='hello'" />
You wouldn't be able to access it in the controller unless you injected $scope and called $scope.myvar
So instead of initializing the variable value in the view the better way to do it would be to first set it in the controller which can be done in a couple of ways:
Controller:
function($scope) {
...
$scope.myvar = 'hello';
...
<input type="text" ng-model="myvar" />
Notice the ng-init doesn't have to be used
The other way is to use c
Controller:
function(){
...
var c = this;
c.myvar = 'hello';
...
HTML:
<input type="text" ng-model="c.myvar" />
Notice $scope doesn't have to be injected.
However, both of these can exist together but they are two totally different objects and you would have to access them respectively to their "scope".
None of this has anything really to do with updating the actual database value if the value is coming from records.
In the previous posts, everyone is trying to tell you that the function "$scope.saveRecord" isn't doing anything.
The function would need to send that data back to the server script and then have logic to actually update the desired record.
An example:
Server Script:
(function(){
if(input){
var gr = new GlideRecord('incident');
gr.get(input.sys_id);
if(gr.getUniqueValue()){
gr.short_description = input.short_description;
gr.update();
}
}
})()
In the gif below you'll see an example of using some "update" functions that do different things.
You can see here that it doesn't necessarily matter whether you use $scope.server.update or c.server.update (there is also ".server.get" that allows you to add items to 'input').
But it does matter knowing how to update the variables' values properly. Another thing to know is that server.update/get has a .then/promise where you can refresh/update the view if necessary. That is where using data directly in the HTML template can come in handy. If the logic allows to limit to manipulating the properties on data, these would automatically get updated once data is updated if one-way binding isn't enforced.
Attached is the widget I created. Play around with it.
I hope this helps and didn't confuse you more.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-08-2020 12:17 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-10-2020 01:54 AM
Hi Chris,
Great explanation. Many doubts have been cleared up with this post.
As you said, we can initialize variables/properties directly in the HTML using "ng-int". Is there a way to access, suppose the value of a input, without initializing anything?
For example,
<input class="m-b" type='text' id='template-scope' name="template-cope" ng-model="templateScope" ng-init="templateScope = 'hello world'" />
In the above code, can I remove the initialization ng-init="templateScope = 'hello world' and still be able to access the input value in the controller? I think we can use $scope.templateScope in the server update. It should give us the value of the input element? OR can we also access the input value using ID attribute of the input?
Thanks a ton again.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-10-2020 07:21 AM
Hi Vinay,
Yes, you would have to access it with $scope.templateScope to access it in the controller.
I only used ng-init in the example so that the value would appear on first load since it wasn't defined in the controller.
To pass that value to the server side you'll need to use server.get() (takes an object as an argument).
"server.update()" only updates the "data" object and passes that back in the "input" object. That's one reason why sometimes you see "data.something" being used in the HTML template.
For example if instead of $scope.templateScope, data.templateScope was used:
HTML
<input ng-model="data.templateScope" />
and in the controller server.update() was used:
Controller:
function($scope,spUtil){
...
$scope.server.update()
//or
c.server.update()
//or
spUtil.update($scope)
...
}
The input would look like this:
{"templateScope": "value here"} or in essence input.templateScope
Server:
(function(){
data.templateScope = "it's raining today";
...
if(input){
console.log(input.templateScope)
}
...
})()
In order to do the same with $scope.templateScope that doesn't exist in the "data" object, the following would need to be used.
HTML
<input ng-model="templateScope" />
(function(){
...
if(input) {
console.log(input.templateScope);
}
...
})
Controller:
function(){
...
$scope.server.get({templateScope: $scope.templateScope}).then(function(resp){
//do something with the resp here to update $scope or view if needed
});
...
}
Server:
(function(){
...
if(input){
console.log(input.templateScope);
}
...
})()
To summarize
"server.update" passes the data object back as input
"server.get" passes the data object back in input any values you define in the object passed as it's argument
In either case you can use the values passed to do things server side such as update a record.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-10-2020 10:43 AM
You sir are the best. You've helped me a lot. Thank you again.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-10-2020 02:54 PM
Hi Chris,
Sorry if I'm bothering you again and again. I've created few more testing widgets and everything has been fine. BUT this particular widget in the opening thread is still not working.
Where I'm stuck is, in the HTML script, I'm not able to send the value of ng-model='incident.short_description' to the server.
<p ng-repeat='incident in data.incidentdata'>
<span ng-if='display'></span>
<input type='text' ng-model='incident.short_description' ng-if='!display'/>
<button ng-click='display=false'>Edit</button>
<button ng-if='!display' ng-click='saveRecord()'>Save</button>
</p>
As you can see, the "incident" fetches the value from data.incidentdata(array of objects) for each iteration. I want to send this value to the server, and update the incident table.