Click items in an ng-repeat to fill another list - javascript

I have a working plunker where you select a thing from a dropdown and it displays data. I would like to be able to click one of those items and it to fill another list below. with other data. I know of ng-click and thats what I am using currently to just pop up an alert with the data I want to be in the list.
This is the section in question:
<div>
<select ng-options="post as post.id for post in allPosts" ng-model="selectPost" ng-change="select()">
<option value="">--select--</option>
</select>
<input type="text" ng-model="searchText" ng-change="search()" />
<ul>
<li data-ng-repeat="item in records | orderBy:'email':reverse" ng-click="moreInfo(item)">
{{item.email}}
</li>
</ul>
</div>
Ideally I want a list like what is in the popup something like:
Email: 'email...'
Name: 'name...'
Body: 'body...'
Like what is in the popup, but to show up below the list of things displayed from choosing the dropdown. (on my webpage it will be over to the right so I am not concerned about formatting, just how to do it). But I DO NOT want the the list to show up if I don't click on an option.
Plunker here.
edit: I am beginning to think maybe an ng-show will do the trick in some fashion, yet, I still do not know how I would pass the data down to the list.

Create a div that will be visible when a message variable is available.
<div ng-show="message">
{{ message }}
</div>
and in your controller, assign the contents for the moreInfo to a $scope.message:
$scope.moreInfo = function(id) {
$scope.message = "Email: " + id.email + "\nName: " + id.name + "\nBody: " + id.body;
};
Here's an updated plunker.

I edited your plunker , hope that is what you wanted.. and it's better for you to use controller as syntax article and you should looki into styleguide too i like this one by John Papa styleguide

It's actually quite straightforward:
First, set your new text to a scope value on click:
$scope.moreInfo = function(id) {
$scope.curResults = "Email: " + id.email + "\nName: " + id.name + "\nBody: " + id.body
//alert("Email: " + id.email + "\nName: " + id.name + "\nBody: " + id.body);
};
Then, simply assign this value to another div:
<div ng-show="curResults">{{curResults}}</div>
Then, whenever you click on the results, curResults is updated and shown in that div.
ng-show="curResults" makes sure the div is only shown when there's a value set to curResults.

Related

Updating View after ng-model change - AngularJS

How would I go about updating an array that is carrying my ng-model after a button click? I cannot bind them because the data I am selecting from is a list. For the data to update I have to change views or refresh but I would like it to update after I click the button
Here is my HTML and where I would like my ng-model text updated
'<span>HVACs: <ct-input disabled="true" ng-model="data.groupLimits[activeIndex].devices" </ct-input> </span>' + '<br>' +
'<span> Add/Remove Device: <ct-input-list list="hvacsList" ng-model="model" </ct-input-list>' + '</span>' +
+ '<ct-button text="Add Device" show="true" ng-click="addDevice()"> </ct-button>'
If the array is loaded initially from a controller method call, just call that method at the end of whatever you are doing, eg
in controller:
$scope.LoadModel = function(){
myService.loadModel(id).then(function(d){
bindArrayToModel();
})
}
$scope.DoClick=function(){
// something
$scope.LoadModel(); // re-load model here
}
in view:

How to add a search box inside select element generated by angular-formly

I am trying to add a search box inside select elements. I am using angular-formly library along with angular-formly-material for material design. I am trying to achieve something similar to angular-material select box as shown in pick a vegetable example
ISSUE
I am able to see the search box but I cannot type into that box. Hence filtering does not work. I have no idea where to put some controller code as described in example.
CODE
formlyConfig.setType({
name: 'select',
template: '<md-input-container>'
+'<label for="{{id + \'_\'+ $index}}">'
+' {{to.label}}'
+' </label>'
+ '<md-select ng-model="model[options.key]"'
+ 'md-on-close="clearSearchTerm()"'
+ 'data-md-container-class="selectdemoSelectHeader"'
+ '>'
+'<md-select-header class="demo-select-header">'
+'<input ng-model="searchTerm"'
+'type="search"'
+'placeholder="Search"'
+'class="demo-header-searchbox md-text">'
+'</md-select-header>'
+'<md-optgroup >'
+'<md-option ng-value="option[to.valueProp || \'value\']" ng-repeat="option in to.options |'
+'filter:searchTerm">{{option[to.labelProp || \'name\'] }}</md-option>'
+'</md-optgroup>'
+'</md-select>'
+'</md-input-container>'
});
I found the solution. I was trying to add a controller to fix this but that was not working. To make this work, I used the link option in formly. Here is the working code.
formlyConfig.setType({
name: 'select',
template: '<md-input-container>'
+'<label for="{{id + \'_\'+ $index}}">'
+' {{to.label}}'
+' </label>'
+ '<md-select ng-model="model[options.key]"'
+ 'md-on-close="clearSearchTerm()"'
+ 'data-md-container-class="selectdemoSelectHeader"'
+ '>'
+'<md-select-header class="demo-select-header">'
+'<input ng-model="searchTerm"'
+'type="search"'
+'placeholder="Search"'
+'class="demo-header-searchbox md-text">'
+'</md-select-header>'
+'<md-optgroup >'
+'<md-option ng-value="option[to.valueProp || \'value\']" ng-repeat="option in to.options |'
+'filter:searchTerm">{{option[to.labelProp || \'name\'] }}</md-option>'
+'</md-optgroup>'
+'</md-select>'
+'</md-input-container>'
,
link: function(scope, el, attrs) {
el.find('input').on('keydown', function(ev) {
ev.stopPropagation();
});
}
});
Formly, Angular, Mat-select, Filtering
This answer for users, who still search answer (now the question watched over 1k). It's solution for Material UI. Hope this help someone.
What you need to do:
create custom type (that is really flexible solution)
provide and import it in app.module
don't use <mat-form-field></mat-form-field> wrapper
use ngx-mat-select-search package or your input for searching into select.
More details in my repo.

Reusable directive with dynamic ng-repeat item name

I have created reusable directive something like dropdown but dropdown open in modal which is working good.
my directive looks like this
<p-select items="deptStations" header-text="Select " text="Select departure..." text-icon="ion-chatbubble-working" text-field="City_Name_EN" text-field2="City_Code" value-field="City_Code" ng-model="deptStation.value">
</p-select>
<p-select items="arrStations" header-text="Select " text="Select arrival..." text-icon="ion-chatbubble-working" text-field="D.City_Name_EN" text-field2="D.City_Code" value-field="D.City_Code" ng-model="arrStation.value">
</p-select>
My directive html is
<ion-content>
<div class="list">
<label ng-repeat="item in items | filter:search" class="item item-text-wrap" ng-click='validateSingle(item)'>
{{item[textField]}} {{textField2 !== '' ? " (" + item[textField2] + ")" : ""}}
</label>
</div>
</ion-content>
Now my issue is when JSON is 1 level it will work as below
[{City_Name_EN:'Abu Dhabi', City_Code:'AUH' },
{City_Name_EN:'Alexandria',City_Code:'HBE' }]
But if I have 2 level JSON than it will not work
[{D:{City_Code:'AMM',City_Name_EN:'Amman'},
D:{City_Code:'BKK',City_Name_EN:'Bangkok'}}]
So how can make this part dynamic {{item[textField]}}
My plunkr http://plnkr.co/edit/GxM78QRwSjTrsX1SCxF7?p=preview
With this kind of dynamic expression of yours, it is always better to have directive consider only a specific contract provided as view model. If the directive consumer has a different data format it should be upto that component to provide the contract that directive needs, it can just map the data to the view model that directive expects. This way you can keep things clean, that would be my opinion.
Now to work around your issue you would need to do a trick to evaluate the multilevel property against an object. You can use $scope.$eval to evaluate any dynamic expression against the scope object. example you can evaluate a dynamic property evaluation of prop1.prop2.prop3 on a scope property item by doing $scope.$eval("prop1.prop2.prop3", item) or $scope.$eval("item." + "prop1.prop2.prop3")
So in your directive:
Added a scope function to get the item text and value:
$scope.getItemName = function(field, item){
//here "this" represents the current child scope of ng-repeat
return $scope.$eval(field, item);
//return this.$eval("item." + field);
}
and
$scope.validateSingle = function(item) {
$scope.text = $scope.$eval($scope.textField, item) + ($scope.textField2 !== '' ? " (" + $scope.$eval($scope.textField2, item) + ")" : "");
$scope.value = $scope.$eval($scope.valueField, item);
...
Update your template to get respective text:
<label ng-repeat="item in items | filter:search" class="item item-text-wrap" ng-click='validateSingle(item)'>
{{getItemName(textField, item)}} {{textField2 !== '' ? " (" + getItemName(textField2, item) + ")" : ""}}
</label>
Plnkr

ng-repeat don't show last piece of text

I have a list of answers that I would like to separate by a comma, but I do not want the last comma to show - how can I do this using ng-repeat and !$last? This is the html I have so far (which is not showing the entire last answer):
<h3 ng-repeat="answer in correctAnswers" ng-show="!$last">
{{answer + "," + " " }}
</h3>
I would recommend not using a separate span and toggling visibility, but use something closer to what you have already attempted:
<h3 ng-repeat="answer in correctAnswers">
{{answer + ($last ? '' : ',')}}
</h3>
No extra directives to be processed, just simple boolean logic w/ concatenation of a string
For convenient, you can try this
<h3 ng-repeat="answer in correctAnswers">
{{answer}}<span ng-show="!$last"> + "," + " "<span>
</h3>

Send dynamic Grails g:select values to JavaScript

I need help trying to get the values from a g:select statement and passing them into a JavaScript function.
So far I have the button
<a href='javascript:void(0)' onclick='runReport("${reportInstance.name}")'>Run Report</a>
Which calls a .js file with
function runReport(reportIn){
var url = reportViewerPath + reportDirectory + reportIn + reportSuffix + promptChain;
window.open(url,'Report Viewer','fullscreen=yes,menubar=yes,status=yes');
}
And this works great. Now the challenge is we have g:select statements on the main .gsp page, but they are variable in number. There could none, or there could be 20, it just depends on the report chosen by the end user.
<g:select id="${prompt.name}" from="${listPromptValues[prompt.name]*.values().collect()}" name="prompt" value="" noSelection="['':'']"/>
This generates the drop down menu with the values for what ever prompt there is.
How do I grab ${prompt.name} and the selected value for every prompt on the page, and then pass that to the .js file as well?
Ideally when runReport() is called, it will pass the reportName, and the prompts will get passed as
&Phone=867-5309&City=NewYork&Name=Jenny
Each url variable would be an optional g:select, so it could also be
&City=NewYork&Name=Jenny
I feel like something like this Related Stack Overflow question would be on the right track.
var prompts = "";
$('$prompt.name').change(function() {
prompts += $(this).text();
$("a").attr('href', function(i, h) {
return h + (h.indexOf('?') != -1 ? "&" : "?") + "selectValue="+val;
});
});
However prompts would have to be a global so that it isn't overwritten every time there is a change.
Edit: Here is the DOM object on the .gsp page
<div id="runButton">
<g:form controller="report">
<g:if test="${reportInstance?.id}">
<a href='javascript:void(0)' onclick='runReport("${reportInstance.name}")'>Run Report</a>
</g:if>
</g:form>
</div>
<ol class="property-list report">
<g:if test="${reportInstance?.prompts}">
<hr>
<li class="fieldcontain" id="prompt">
<g:each var="prompt" in="${reportInstance.prompts}">
<span id="prompts-label" class="property-label">
<g:message code="report.prompts.label" default="${prompt.description}:" />
</span>
<g:if test="${prompt.datatype.type == 'DropDown'}">
<g:select id="${prompt.name}" from="${listPromptValues[prompt.name]*.values().collect()}" name="prompt" value="" noSelection="['':'']"/>
<br>
</g:if>
</g:each>
</li>
</g:if>
</ol>
And then in run.js
function runReport(reportIn){
var promptChain = $("#prompt :select[name=prompt]").serialize();
reportName = reportIn;
...
}
Am I going about this incorrectly?
Edit 2: Grabbing the prompts like it should
...
<g:if test="${prompt.datatype.type == 'DropDown'}">
<g:select id="${prompt.name}" from="${listPromptValues[prompt.name]*.values().collect()}" name="${prompt.name }" value="" noSelection="['':'']"/>
<br>
</g:if>
...
and the jQuery
var promptChain = jQuery('select').serialize();
You're using jQuery, so just serialize the form's select elements. Doesn't matter how many their are. No need to track some global variable.
function runReport(reportIn) {
var promptChain = $("select[name=prompt]").serialize();
....
}
Here's a jsFiddle

Categories