ng-repeat don't show last piece of text - javascript

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>

Related

React: Method to create inputs from template tags in a string of html

Phew okay here we go...
I have a string of HTML that comes from an API response. It's HTML that builds an email template. Within that HTML that's returned there are multiple instances of template tags defined by double curly brackets {{ }}.
Part 1
What I would like to achieve is creating a function that finds all instances of a template tag, {{ tag }}. Once found I would like to create an object with all the key's being those tags, stripped of the brackets, that could be saved to the state.
So let's say the html contains these tags
{{ title }}
{{ sub_title }}
{{ caption }}
{{ body_text }}
We would create an object looking like
{
"title": " ",
"sub_title" ; " ",
"caption": " ",
"body_text": " "
}
and save it to the state. this.state.inputs for example
Part 2
With this object in the state, we can create a number of inputs with the name attribute set to the object key.
<input name="title" />
<input name="sub_title" />
<input name="caption" />
<input name="body" />
Part 3
This I know how to approach, it would be updating state with the value of those inputs. Not a problem.
What do you think the best method to approach this problem would be? Discussion is always welcome. I would like to learn how to approach these types of problems.
How about making a function and running the for statement as shown below?
Below is an idea, not an exact action code.
let object1 = {
"title": " ",
"sub_title" ; " ",
"caption": " ",
"body_text": " "
}
for (const [key, value] of Object.entries(object1)) {
<input className={key} props={value}/>
}

Slice ng-repeat with AngularJS

An easy question from a noob in Angular.
I have my ng-repeat like this:
ng-repeat="f in drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR]
and I want to slice the last record because it's alway empty and it comes like that from the WS but I dont know how to achive this in AngularJS.
Inside ng-repeat you have available a variable $last.
example
<div ng-repeat="item in [1,2,3,4]">
<div ng-if="!$last">{{item}}</div>
</div>
See more https://docs.angularjs.org/api/ng/directive/ngRepeat
Use the limitTo filter.
ng-repeat="f in drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR] | limitTo:-1"
Alternatively, just show the last item in the list.
<div data-ng-bind="drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR][drillDownList['D' +
d.merchMetrics.DEPT_NBR + 'CG' +
d.merchMetrics.CATG_GRP_NBR + 'C' +
d.merchMetrics.DEPT_CATG_NBR].length-1]"
</div>
Might I suggest that you do all that concatenation in the Controller? If you do it on the View side, it's going to execute every digest.

Click items in an ng-repeat to fill another list

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.

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-class not responding to change in model in Angular?

Having searched extensively, got some help from A ternary in templates and getting partially functional results, I'm 99% sure I'm doing it 99% right, but...obviously not completely, so I'm here.
The basic HTML structure:
<ul>
<li class="week-row" ng-repeat="week in weeks" id="{{$index}}">
<ul class="tiles" ng-class="{ 'expanded': week.isOpen, 'hidden': !week.isOpen }">
<li class="day-tile"
ng-class="{'active': (activeDay == $parent.$index + '-' + $index) }"
id="{{$parent.$index + '-' + $index}}"
ng-repeat="day in week.days"
ng-click="fn2({ week: $parent.$index, day: $index })">
<!-- moved ng-class to here, and it works? -->
<div>some stuff in here</div>
</li>
</ul>
</li>
</ul>
The stuff in the controller that sits above it:
$scope.activeDay = null;
$scope.fn1 = function() { $scope.activeDay = '0-0'; }; // this works, and sets the first one active
$scope.fn2 = function(data) { $scope.activeDay = data.week + '-' + data.day; }; // this sets the first one not active, but none of the others go active
I'm trying to set one of the nested list items to be active, based on its indexes in the nested arrays by using the $parent.$index and $index as a string, joined by '-'.
What's throwing me off is that console.logging $scope.activeDay, data.week + '-' + data.day, and both == and === comparisons come out exactly as I would expect, (the same strings, true, true) and it works on initial load when I set activeDay to '0-0', so I'm clearly missing something in my binding or...?
After finding this: https://egghead.io/lessons/angularjs-the-dot - I tried setting it up as an object so I couldn't get into some weird isolate scope nonsense: $scope.tiles = { activeDay: null }; and then setting that property from my functions, to no avail.
Why does setting it initially work, while changing it later does not? Is this improper binding of classes or...?
I also tried it with
class="day-tile {{activeDay == $parent.$index + '-' + $index ? 'active' : ''}}"
and that works initially, but breaks afterwards...
Your help is much appreciated!
UPDATE:
After moving ng-class="{'active': (activeDay == $parent.$index + '-' + $index) }" onto the div inside the ng-repeated .day-tile li, it works fine.
Any ideas why this might be?
From the info you provided I have this working jsFiddle.
I removed the classes you were hard coding to true and stuck them in class="". The classes you were evaluating expressions for i put in ng-class="".
I attached your functions to $scope so ng-click could find them. So $scope.fn2 rather than var fn2.
Without knowing more details, I would say this should fix your problem.
Code Changes:
controller:
$scope.activeDay = null;
$scope.fn1 = function() { $scope.activeDay = '0-0'; };
$scope.fn2 = function(data) { $scope.activeDay = data.week + '-' + data.day; };
partial:
<ul class="tiles" ng-class="{'expanded' : week.isOpen, 'hidden' : !week.isOpen}">
<li class="day-title"
ng-class="{'active': (activeDay == $parent.$index + '-' + $index)}"
id="{{$parent.$index + '-' + $index}}"
ng-repeat="day in week.days"
ng-click="fn2({ week: $parent.$index, day: $index })">
//put expression here so you can see the list item
{{week.day}}
</li>
</ul>

Categories