Within an *ngFor loop, where I'm building a list of search results (mat cards) with sample reading texts, I want to allow the user to click on one of them to read more, and open a route to a document template populated with the right doc.
This static HTML works with routerlinkactive catching the params in the docview page...
<button mat-button [routerLink]="['/docview', {sDocName: 'AW010001'}]">READ MORE...</button>
I want to replace the hardcoded Doc ID 'AW010001' with the appropriate ID for each iteration through the *ngFor. But this code fails...
<button mat-button [routerLink]="['/docview', {sDocName: '{{sDocIDs[i]}}'}]">READ MORE...</button>
The error I get is the typical...
Parser Error: Got interpolation ({{}}) where expression was expected
at column 25 in [['/docview', {[sDocName]:'{{sDocIDs[i]}}' }]]
Check out Angular 5-Routing (Practical Guide)
To high-light the main points:
Update the route table:
{ path: 'book/:id', component: BookDetailsComponent, }
Use this format:
<a [routerLink]="['/book',b.Id]">Details</a>
So in your example I think it should look like this:
<button mat-button [routerLink]="['/docview', sDocIDs[i]">READ MORE...</button>
With ngFor loop i guess that you only need something like this : routerLink="/docview/{{sDocName.sDocIDs}}" + proper function in component
Go to angular.io, example is shown in tutorial
Actually... I ended up moving the routerLink functionality into a function in my .ts file for that component...
readMore(sDoc: string) {
this.router.navigate(['/docview', {sDocName: sDoc}]);
window.scrollTo(0, 0);
}
Then in my HTML, I use a variable that is associated with all the other story metadata... in this case I used an array for development, but will eventually replace that array variable with an element of a data model for the stories.
<button mat-raised-button (click)="readMore(DocIDs[i])">READ MORE...</button>
This is working well for me.
Related
Here is the structure of the toggle:
<div data-id="thisIsTheID" class="abc">
<div class="edf">
<button value="false"></button>
</div>
</div>
The trigger only works with click >> all elements >> click classes contains edf. I tried click element matches css selector
div.abc
div.abc *
div.abc button
but none will work as trigger.
However, I want the data-id as variable in Google Tag Manager in order to differentiate between different toggles.
How do I create a trigger that works and how do I get the variable?
Here the actual code and debugger view:
Try making a custom JS variable like so:
function(){
return {{Click Element}}.parentElement.getAttribute("data-test-id");
}
It should return the value of your attribute on click.
But the classes look auto-generated. They feel like they can and will change on cache refresh or on front-end builds. I would try to use selectors like div[data-test-id] * or even div[data-test-id=isAgePolicy] *
I am trying to modify the project ngImgCrop (https://github.com/alexk111/ngImgCrop) for allowing crop multiple images in the same page, but I do not know how many images I would need, this is created dynamically. So, I need to associate to the 'image' field of a dynamic value, and at the same time I put this variable in my scope. The problem is that this label is not evaluating the angular code.
<div class="cropArea" id="{{'person'+person.Id}}">
<img-crop image="{{'person'+person.Id}}" result-image="myCroppedImage"></img-crop>
</div>
Even when they have the same code, when the page is loaded the html code shows:
<div class="cropArea" id="person12345">
<img-crop image="{{'person'+person.Id}}" result-image="myCroppedImage"></img-crop>
</div>
In my scope since the beginning the variable $scope.person12345 is created, but It is impossible to make the binding without this part.
What can I do?
Note:
In my init() function I create all the variables:
angular.forEach(persons, function (person, index) {
$scope['person'+person.Id]='';
});
I actually can see the variable $scope.person12345 when the page is loaded. In any case why does the expression worked for the div and not for the img-crop?
Please put your expression as a function which will execute in the Controller. string(appending string) will return by a function like below.
<div class="cropArea" id="{{'person'+person.Id}}">
<img-crop image="getImagePath(person.Id)" result-image="myCroppedImage"></img-crop>
</div>
Controller like below:
$scope.getImagePath = function(id){return 'person'+id+'.png';};
Some how there is no parser available in the directive of image, that's why you need to give parsed expression via a controller.
How i can set dynamic name to angular 2 component?
I have next code in my template:
<{{component} [data]="data" [anotherData]="anotherData"></{{component}}>
And I want do define componentName in my class
component: string = 'component';
Because now i have next error:
Uncaught (in promise): Template parse errors:
Unexpected closing tag "{{component}" ("
<div [ngSwitch]="contactService.contact.cat">
<div *ngSwitchWhen="'person'">
<persons-edit [primary]="true"></persons-edit>
</div>
<div *ngSwitchWhen="'business'">
<businesses-edit [primary]="true"></businesses-edit>
</div>
<div *ngSwitchWhen="'place'">
<places-edit [primary]="true"></places-edit>
</div>
</div>
This is what I use in my app. I have the three components defined, and use a switch to show the one I want. I get the selection here from a service, but you could get it from your root component. Something like this:
#Component {
selector: 'dynamic-component',
....
}
export class DynamicComponent{
#Input selectedcomponent : string;
}
Then use it in a template:
<dynamic-component [selectedcomponent]="person"></dynamic-component>
And instead of using a service, switch on "selectedcomponent".
The Answer is simply You Can't !!
While defining your component you must have to declare name of that component(i.e selector property) as well as class name. without declaring component name you can't create component.
so in your case there are option is either you create no. of components and call whenever you need of that component or create dynamic input value of that component so as per need set your dynamic value and get usng #Input. because for each component there is diff. template and logic as well, so better is to create new components and use as per need.
yes no doubt you can set dynamically data to that component like ID's ,name, custom input etc etc.
hope it clears everything if not comment here !
You cannot dynamically assign names to components the way you try to do it.
However, you can dynamically assign ids to your elements with [attr.id]="id_string_expression"
Most likely you can solve your problem that way.
Something like:
<my-component [attr.id]="name+number" [data]="data" [anotherData]="anotherData"></my-component>
I beginning on this framework.
And I've a question about update a controller from another controller.
I know this question has many times asked.
But it's not like my problem.
I can resolve my problem with rootScope, but I don't like (Am I wrong ?)
This is my example:
http://jsfiddle.net/1Lwg20wz/
I thought it would update automatically with this part of code:
this.article = articleService.article;
I would like to update my PanelController when I click on "Read news".
How do you do ?
What is the best practice ?
First a couple of small issues in your example:
In the following HTML:
<a href="#" ng-click="selectArticle(article.index)" class="btn btn-default">
View news
</a>
Change href="#" to href="". Otherwise it will navigate to the root of your application instead of executing the ng-click.
In the same HTML change ng-click="selectArticle(article.index)" to ng-click="main.selectArticle(article.index)".
Now to the main issue.
In the PanelController you have the following code:
this.article = articleService.article;
This will copy the reference stored in articleService.article to this.article.
If articleService.article held a reference to the article object with id 1, this.article now also holds a reference to that object. They are however, two different references.
You have the following code to set the selected article object:
this.selectArticle = function(setArticle) {
articleService.article = articleService.articles[setArticle - 1];
};
Now articleService.article will hold a reference to another article object, for example with id 2. But, this.article in PanelController will still hold a reference to the article object with id 1.
The easiest solution to achieve what you want is to use the original articleService.article reference in your view, instead of creating a copy of it.
In PanelController
this.articleService = articleService;
In HTML:
<h1>{{panel.articleService.article.title}}</h1>
<p>{{panel.articleService.article.content}}</p>
Demo: http://jsfiddle.net/7ccop2hy/
I am facing a strange behavior when testing an Angular JS application with protractor.
Considering this HTML structure , I would like to click on the inner div which is a filter.
<div ng-hide="term.selected" ng-click="selectFilter('target',term.value)" class="listItem">
<div>
<label class="ng-binding">ZECPFICO00</label>
<span class="listItemNum ng-binding">157</span>
</div>
</div>
Here is my locator :
element(by.repeater('term in facets.target | filter:ecSearchText').row(1)).click ();
When executing this code my webdriver cursor goes to the filter in the web page but and tries to click on the filter however the click does not work and therefore the filter is not applied.
1 - You don't need to specify the filters when using by.repeater it is optional
2 - Sirk is almost there, you need to continue chaining your promises, below an example of clicking on a div, you can use any by method here..
var elements = element.all(by.repeater('term in facets.target'));
elements.first().then(function (term) {
term.findElement(by.css('div')).then(function (div) {
div.click();
});
});
3- You could also do it this way:
element.all(by.repeater('term in facets.target')).get(0).click();
hmm I've never seen or used a locator that way where you have .row(1), but I am a noob so that just might be my own ignorance, however you could try something like the following:
element(by.repeater('term in facets.target | filter:ecSearchText')).then(function(rows){
rows[0].click();
});
That should click on the first row of the repeater. 'rows' would contain all the rows as an array.