Show textareas values in parent component as a list & not showing tabs on page load - arrays

I created a form with Angular Material, inside the form I have a mat-radio-group for radio buttons, and mat-tab-group
For tabs, each one of this tabs have an input. I have two questions.
1 - The tab group doesn’t show when the page loads, I have to click in a radio button to see the tabs, I don’t know why this is happening.
2 - I am getting the values from the textareas and I am showing them in the parent component, When I write a new value in the text area, this one replace the previous value, but I need all the values from the different textareas.

1st issue - not able to see tabs on reload/load
actually, as per the code, we are getting console errors, and because of that, we are not able to see tabs. it is breaking at the radio group itself.
console errors
Fix for the above issue - remove the formControlName="titleAction" for each radio button.
2nd issue - not getting all tabs data in a parent from child comp
so... here you are not sending all tabs data. that is the actual issue.
I did a few changes in child and parent as per your expected result.
sending array from child like below
submit() {
this.updateDataEvent.emit({formdata:this.form.getRawValue(), tabs: this.tabs});
}
and changed code in the parent component while updating a few global variables
updateData(selection: any): void {
this.titleScreening =
selection.formdata.titleAction === 'change'
? selection.formdata.titleText
: 'Original Title';
//Empty Inputs
if (this.titleScreening === '') {
this.titleScreening = 'Original Title';
}
this.divTag = this.divTag2 = ''
selection.tabs.forEach((x) => {
// this.name = x.fullName;
var appendElement = '<li> <span> Name </span>' + x.name + '</li>';
this.divTag = this.divTag + appendElement;
// Show in parent component
var appendElement2 = '<li> Value: ' + x.value + '</li>';
this.divTag2 = this.divTag2 + appendElement2;
});
// selection.fullName === ''
// ? (this.divTag = '')
// : (this.divTag = appendElement);
}
stackblitz

Related

AngularJS- how to return multiple buttons? Return a promise that resolves to an array?

I have an AngularJS application, and on one of the pages, there is a button that opens a dialog allowing the user to configure a particular widget. That widget displays a table, and I have recently added the functionality to allow the user to add a single button to a given table cell. This functionality all currently works correctly.
I am now trying to extend the functionality, to allow a user to add multiple buttons to a single table cell.
The way that the user currently adds a button to a cell, is by typing the address of the page that they want to add the button for into a text field on the dialog- the page that they type must be preceded with a : character. However, that text field is also used to display variable values, so for example, to display a variable value, they would type the name of the variable, i.e. myVariable, but to add a button which would link to the Home page, they would type :pages/home.
The value that they type into the text field is converted to the appropriate object for display in the table by a function called toItemObj(item).
This function is defined with:
function toItemObj() {
...
switch(widgetObj.name) {
case 'table':
...
widgetObj.table = angular.copy($scope.widget.table);
...
var multiBtns = ";";
var btnArray = [];
var btnTmplArray = [];
var pageTitle;
...
angular.forEach(widgetObj.table.rows, function(row) {
if(row.length > 0) {
reducedRows.push(row.map(
function(vrbl, idx) {
...
if(widgetObj.table.header[idx].startsWith(":")) {
if(vrbl.vrbl.includes(multiBtns)) {
btnArray = vrbl.vrbl.split(multiBtns);
if(btnArray[0].startsWith(":")) {
brnArray[0] = btnArray[0].split(":")[1];
}
var btnArrayBtn = 0;
angular.forEach(btnArray, function() {
var btnTmpl = $compile(
'<a href="javascript:;" ng-click="goToPage(target)"' +
'class="btn btn-xs btn-brand">Go to page</a>')
toVrblItemObj(btnArray[btnArrayBtn]);
compiledBtns.push(btnTmpl);
console.log("compiledBtns: ", compiledBtns);
})
} else {
console.log("Vrbl does not include multiBtns: ", vrbl.vrbl);
}
} else {
console.log("Value of widgetObj.table.headers[idx]: ", widgetObj.table.headers[idx]);
}
console.log("Returning vrbl.vrbl: ", vrbl.vrbl);
return vrbl.vrbl;
}
));
}
});
widgetObj.table.rows = reducedRows;
...
break;
In the if(vrbl.vrbl.includes(multiBtns)) { block, I am checking whether the value given to the button by the user contains a ; character, and if it does, I am splitting that string on the ; character, and compiling a button for each of the split elements, then pushing that compiled button to a list called compiledBtns.
The problem I'm having is with returning multiple buttons when they've been compiled...
When I load the page with this code as it is above, and try adding a button to a table cell, if I just add a single button to the cell (i.e. type something like :pages/page1 into the field in the dialog, then that button is displayed correctly. But, if I try to add more than one button to a table cell, (i.e. type something like :pages/page1;pages/page2 into the field in the dialog), then the compiled buttons are not displayed, and I just get the text that I actually typed:
I thought that this might be because my return statement is only returning the single vrbl.vrbl element (i.e. a single button), so I tried changing it to:
if(widgetObj.table.headers[idx].startsWith(":")) {
console.log("column heading starts with : - returning compiledBtns- ", compiledBtns);
return compiledBtns;
} else {
return tag.tag;
}
i.e. if the column is a 'buttons' column (the heading starts with a : character, then it should return the list of compiled buttons, but if not, then it should return a variable.
Doing this caused the table to be displayed as:
i.e. it stops even the cells with only one button from showing the button...
The console is showing me that the buttons are being compiled:
compiledBtns: (2) [ƒ, ƒ]0: ƒ publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn)1: ƒ publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn)length: 2__proto__: Array(0)
ctrl.js:467 Returning tag.tag: :pages/auth;pages/userpage1
but for some reason, they're just not being shown...
Can anyone explain what I'm doing wrong here? How can I get my function to return and display multiple buttons in the same table cell?
Edit
I've just noticed that when only entering one button in a table cell, the button is only displayed/ rendered as a button when you select it from the 'autocomplete' list that's displayed when you start typing- i.e. if you type out the page address in full, and click 'Preview' on the dialog, the button is not displayed in the table- it just shows the textual address that you typed.
When trying to add multiple buttons to the table cell, obviously the autocomplete doesn't recognise any pages with the address of two combined page address (separated with a ;), so you can't select more than one page from the drop down at a time.
How would I enable the selection of multiple items from the autocomplete drop down? The autocomplete functionality is defined in the HTML:
<div class="repeat-item-animation" data-ng-repeat="row in widget.table.rows">
<div class="row">
<div class="col-sm-12 input-addon-btn widget-picker-table-row-input">
<tags-input min-length="1"
um-max-tags-strict
key-property="tag"
data-ng-model="row"
display-property="tag"
template="tagItem.html"
replace-spaces-with-dashes="false"
on-tag-adding="onAddingTagItem($tag)"
on-tag-added="warning.rows = undefined"
um-tags-input-warning="{{warning.rows}}"
max-tags="{{widget.table.headers.length}}"
placeholder="Start typing a tag name or some text">
<auto-complete min-length="1"
load-on-focus="true"
load-on-empty="true"
display-property="tag"
select-first-match="false"
template="autocomplete.html"
source="autocompleteTagsFilter($query)">
</auto-complete>
</tags-input>
<a href data-ng-click="widget.table.rows.splice($index, 1)"
class="btn-icon btn-icon-sm btn-config btn-danger">
<span class="glyphicon glyphicon-minus-sign"></span>
</a>
</div>
</div>
I've Google'd a bit, but can't find any properties for the above <auto-complete> tag that would appear to enable selection of more than one element... Anyone have any suggestions?
Edit
So it seems that the auto-complete feature is actually a part of the implementation of ngTagsInput, which it seems the application is using to provide this functionality. From reading its documentation, it seems that the source parameter is the one I want to be using to return an array of strings (i.e. the links for multiple pages that I want to add buttons for). In the 'Parameters' table under the 'Usage' section of the autoComplete directive in ngTagsInput, the description of source is:
Expression to evaluate upon changing the input content. The input value is available as $query. The result of the expression must be a promise that eventually resolves to an array of strings.
In my application, the source attribute is currently set to the function autocompleteTagsFilter($query), which is defined with:
$scope.autocompleteTagsFilter = function(query) {
// Use last valid query keyword instead if input keyword is undefined
// When the first character of the tag that the user enters is a ':',
// the drop down should display a list of available user pages, not tags.
// Put the 'if(!query && lastTagQryKw)' inside the 'else', so that this
// is run whenever the entered tag name doesn't start with ':'
if (query.startsWith(":")) {
console.log("query starts with ':' ", query);
/*Check whether string has a ';' & split it if it does */
if(query.includes(";")) {
var strings = query.split(";");
console.log("strings[0]: ", strings[0]);
console.log("strings[1]: ", strings[1]);
var strings0 = strings[0].split(":")[1];
// console.log("strings0: ", strings0);
var strings1 = strings[1].split(":")[1];
// console.log("strings1: ", strings1);
/*Now need to pass each string to 'toTagItemObj(), to make it a tag item object', so that it can be displayed as a button */
angular.forEach(strings, function(string, btnString) {
// console.log("angular.forEach - value of string: ", string);
// console.log("angular.forEach - value of btnString: ", btnString);
toTagItemObj(string);
})
}
// Split the 'query' search string on ':', to use only the string
var buttonsQuery = query.substring(1);
if (!buttonsQuery && lastTagQryKw) {
buttonsQuery = lastTagQryKw;
}
/*check whether the buttonsQuery variable contains a ';' - if it does, split it */
if(buttonsQuery.includes(';')) {
console.log("buttonsQuery includes ; - ", buttonsQuery);
var btnsToDisplay = buttonsQuery.split(";");
console.log("btnsToDisplay: ", btnsToDisplay);
}
// Declare variables to be used in 'for' loop
var userPages = pagesPresets;
var page;
var result = [];
// 'For' loop should iterate through the list of user pages,
// and remove path, so that only the page name is shown
for (page in userPages) {
page = userPages[page];
// If the page key starts with 'buttonsQuery', and its length
// is greater than 6 (i.e. just 'pages/' shouldn't be displayed)
// add the page to the list of pages to be displayed.
if (page.key.startsWith(buttonsQuery) && page.key.length > 6) {
result.push(page.key);
}
};
if (result.length > 0) {
lastTagQryKw = query;
}
// Return the list of pages that match what the user has typed
return result;
// Otherwise, if the user types something that does not start with ':',
//then it should be a tag- search for tags that match this term
} else {
if (!query && lastTagQryKw) {
query = lastTagQryKw;
}
var result = Object.keys(fxTag.getTags()).filter(function(name) {
return name.indexOf(query.toLowerCase()) !== -1;
});
if (result.length > 0) {
lastTagQryKw = query;
}
return result;
}
};
As it currently stands, this autocompleteTagsFilter() function is returning an array of strings in its return statement. The array of strings is what's shown in the list of auto-complete options available, but the button is only actually created when selecting one of them.
According to the documentation, I need this to return a promise which resolves to an array of strings, but I'm not sure how I'd do this... Can anyone suggest a way I might make this function return a promise that resolves to an array of strings?
Edit
The template code for the markup/ cell rendering as it currently stands is:
angular.module('app.widget').run(function($templateCache) {
// Add basic suggestion template of autocomplete
$templateCache.put(
'autocomplete.html',
'<div class="pull-left autocomplete-text autocomplete-full-text">' +
'<span ng-bind-html="$highlight($getDisplayText())"></span></div>'
);
$templateCache.put('tagItem.html',
'<div data-ng-click="data.nounit = data.isTag && !data.nounit" ' +
'class="glyphicon-clickable" um-tag-item-disabled>' +
'<span class="tag-item-icon glyphicon glyphicon-tag" ' +
'data-ng-show="data.isTag"></span><span class="tag-item-text">' +
'{{$getDisplayText()}}</span><span class="tag-item-unit" ' +
'data-ng-hide="!data.units || data.nounit">({{data.units}})</span>' +
'<a class="remove-button" ng-click="$removeTag()">' +
String.fromCharCode(215) + '</a></div>'
);
}).controller(...){
I tried changing this to use an ng-if, so that it would show a different template for when buttons should be displayed for multiple pages, but this gives me an error in the console that says:
Error: [ng:areq] Argument 'WidgetPickerCtrl' is not a function, got undefined
I got this error after changing the template to:
angular.module('ultimetric.widget').run(function($templateCache) {
// Add basic suggestion template of autocomplete
$templateCache.put(
'autocomplete.html',
'<div class="pull-left autocomplete-text autocomplete-full-text">' +
'<span ng-bind-html="$highlight($getDisplayText())"></span></div>'
);
$templateCache.put('tagItem.html',
'<ng-if="data.isPages">' +
'<div data-ng-click="data.toPageBtn = data.isPages && !data.toPageBtn" ' +
'class="glyphicon-clickable" um-tag-item-disabled>' +
'<span class="tag-item-icon glyphicon glyphicon-tag" ' +
'data-ng-show="data.isBtn"></span><span class="tag-item-text">' +
'{{$getDisplayText()}}</span><span class="tag-item-text">' +
'data-ng-hide="!data.units || data.toPageBtn">({{data.unnits}})</span>' +
String.fromCharCode(215) + '</a></div>'
'<div data-ng-click="data.nounit = data.isTag && !data.nounit" ' +
'class="glyphicon-clickable" um-tag-item-disabled>' +
'<span class="tag-item-icon glyphicon glyphicon-tag" ' +
'data-ng-show="data.isTag"></span><span class="tag-item-text">' +
'{{$getDisplayText()}}</span><span class="tag-item-unit" ' +
'data-ng-hide="!data.units || data.nounit">({{data.units}})</span>' +
'<a class="remove-button" ng-click="$removeTag()">' +
String.fromCharCode(215) + '</a></div>'
);
}).controller(...){
Any ideas how I can get the autocomplete to show multiple buttons at the same time?

CQ/AEM extjs get selection dropdown box text, and get page path

Say I have a component with dialog drop to parsys on a content page /content/phonegap/ss/en_gb/login/home/test1/jcr:content/par/productimage
now inside the dialog i have something like
I wish to get $PATH append to URL and send selected device e.g the text 'Device ID:HTC_10_GOLD', to servlet in this dialog listener extjs:
<deviceAndColour
jcr:primaryType="cq:Widget"
allowBlank="{Boolean}false"
fieldLabel="Device and Colour"
name="./deviceAndColour"
options="/bin/reference/data/device.devices.json$PATH"
type="select"
xtype="selection">
<listeners
jcr:primaryType="nt:unstructured"
selectionchanged="function(pathfield) {
var selected = this.findParentByType('form').find('name', './deviceAndColour')[0].getText();
console.log( this.findParentByType('form').find('name', './deviceAndColour')[0].getText());
$.getJSON('/bin/reference/data/device/availablecolour.availablecolour.json$PATH?selectedDevice=' + selected + '&colour=red', function(jsonData){
selectBox.setOptions(jsonData);
});
}" />
</deviceAndColour>
So bascially, the console.log( this.findParentByType('form').find('name', './deviceAndColour')[0].getText()); is not working as I expected, neither the $PATH inside the dialog listener js, it does not retrieve the path at all.
Apart from above attempt, I know var selected = this.findParentByType('form').find('name', './deviceAndColour')[0].getValue(); this will get the value asscociated with the select correctly, but I do not need value, I just wish to getText(), and get the current $PATH in extjs.
another questions, you may noticed $.getJSON('/bin/reference/data/device/availablecolour.availablecolour.json$PATH?selectedDevice=' + selected + '&colour=red'
how do I skip the & in this listner, as if i use & directly, project won't even build. there must be someway to skip & and let extjs treat as part of the string to send request
Anyone expereinced this before? please suggest with code example.
Thanks
Getting the text of the option selected:
function(field,value){
for(var i = 0; i < field.options.length; i++) {
if(field.options[i].value === value) {
console.log('Selected: ' + field.options[i].text);
break;
}
}
}
Getting the path to the resource being edited:
function(field,value){
console.log("Resource:" + field.findParentByType("dialog").path);
}
Documentation: https://docs.adobe.com/docs/en/cq/5-6/widgets-api/index.html?class=CQ.form.Selection
UPDATE
Please try the following code adapted to your scenario (I also refactored the code to make use of params when providing query parameters. There is no reason why this shouldn't work.
function(field, value) {
var selected = '';
var path = field.findParentByType("dialog").path;
// get text of option selected
for(var i = 0; i < field.options.length; i++) {
if(field.options[i].value === value) {
selected = field.options[i].text;
break;
}
}
var params = {
selectedDevice: selected,
colour: 'red'
}
$.getJSON('/bin/reference/data/device/availablecolour.availablecolour.json'+path, params, function(jsonData){
// FIXME: how are you getting the "selectBox" reference?
selectBox.setOptions(jsonData);
});
}

Show data in inputbox from 1 object and save it in using another object

I'm clicking a table row to edit the fields in a modal. The modal must have 2 functionalities (Add or Edit) depending on the GET request data like below.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
}
HTML
<label ng-if="editedObject.email">{{editedObject.email}}</label>
<label ng-if="!editedObject.email">Email</label>
<input ng-model="newObject.email" />
I am able to display the object in the labels, but that's not much help, because the data needs to be shown in the input boxes to be Edited and Saved.
How can i show the data from editedObject.email in the input, so i can save it using newObject.email?
I tried ng-init="editedObject.email", but it doesn't work. Is there some other ng-something that does this or i should be doing it in another way?
Update:
Edit and Update Methods, both are in the mainController.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
})
}
//Controller for the Modal
function DialogController($scope, $mdDialog, editedObject) {
$scope.editedObject = editedObject
$scope.submitObject = function(newObject) {
$http.post('/api/interview', newObject)
}
}
You have to make a deep copy from editObject.email to newObject.email. This could be done this way in controller after editOject.email has a value assigned.
$scope.newObject.email = angular.copy($scope.editObject.email);

Accordion ionic resize and scroll

I have an accordion in ionic. To reset the screen size when the user clicks to open one of the items I used $ionicScrollDelegate.resize();. However remains a problem, when I click on an item with great content and then click on the item that comes down the content goes up, because closed the item above, but the screen does not scroll together, so the user does not see the content of the item he just clicking.
What I need is that the screen always scroll to the beginning of the contents of the clicked item.
I tried this with
$IonicScrollDelegate.$getByHandle('handle_' + group.id).scrollTop();
But I must have done something wrong because it returns an error that we could not find the delgate-handle. Searching I found some people saying to use $timeout but it also did not solve my problem.
Below is the code I'm using for the controller:
.controller('CatalogoCtrl', function($scope, categories, $ionicScrollDelegate) {
Scope.categorias Categorias.all $ = ();
$scope.toggleCategoria = function(group) {
if ($scope.isGroupShown(group)) {
$scope.shownGroup = null;
} else {
$scope.shownGroup = group;
}
$IonicScrollDelegate.$getByHandle('handle_' + group.id).scrollTop();
};
$scope.isGroupShown = function(group) {
return $scope.shownGroup === group;
};
})
It looks like you have a typo in your code, because you have occurrences of $IonicScrollDelegate (starting with an uppercase I) and $ionicScrollDelegate (starting with a lowercase i).
You should therefore change all occurrences of $IonicScrollDelegate to $ionicScrollDelegate.

How to set blank or null value of input field on back button press in angularjs

Could you please tell me how to set blank or null value for an <input> field so it is blank when I press the back button press in AngularJS?
I will explain my question:
When I run index.html file, it shows one form.
I fill name :"naveen" and password :"sharma" and click "Forget password".
It still show sign up page
When I click the back button ("present on top header or square one"), it shows the first page again - i.e. the login page with same (original) entry values name ="naveen" and password =`"sharma".
I need to reset these fields i.e. means it shows blank or null..
Here is my code:
function authenticationCntrl($scope,$state,Auth) {
$scope.user = [];
console.log('=====authenticationCntrl controller call')
console.log($scope.user.username)
console.log($scope.user.password)
$scope.forgetPassword = function () {
if($scope.user.username==Auth.username && $scope.user.password==Auth.password ){
$state.go('signup')
}
}
}
You can see it running here http://goo.gl/P5RsDU
to check out put please press preview button
Change for forgetPassword function as shown below:
$scope.forgetPassword = function () {
if($scope.user.username==Auth.username && $scope.user.password==Auth.password ){
$state.go('signup');
$scope.user.username = '';
$scope.user.password ='';
}
}

Resources