How do I pass a model to a razor pages custom helper - html-helper

I want to pass a model to a custom razor helper to perform a repetitive Razor generation task. The code that I want to be generated will look like:
#foreach (Place P in Model.Places)
{
<div class="col-md-4 clsBorder">
#if (P.prop1 != null && P.prop1 != "")
{<div class="row ">
<div class="col-6">
#Html.DisplayNameFor(model => P.prop1 )
</div>
<div class="col-6">
#Html.DisplayFor(model => P.prop1 )
</div>
</div>}
#if (P.prop2 != null && P.prop2 != "")
{<div class="row">
<div class="col-6">
#Html.DisplayNameFor(model => P.prop2)
</div><div class="col-6">
#Html.DisplayFor(model => P.prop2)
</div>
</div>}
</div>
}
Obviously there may be more then 2 Place objects in Model.Places, and many more then prop1 and prop2 in each Place object.
So how do I pass the Places object, which may be a List<customClass>, and have the code generated for each property?

How about, you name your helper method and put parentheses around the parameter model.
#Util.MyUtilMethod(Model.Places)
assuming your helper method calls a service that renders the template to string
public static class Util
{
//...
public async string MyUtilMethod(List<customClass> places)
{
return await this._viewRenderService.RenderToStringAsync(
"blahContext/blahAction",
new blahContext.blahModel { Places = places});
}
//...
}
an example of how to Render a Razor Page to string.

Related

Angular - Rendering filtered array issue

I'm following this tutorial and I'm stuck in this feature where I have to display a filtered array (object coming from firebase) when clicking an anchor. I followed all the implementation steps but I'm missing something...The code:
HTML:
<div class="row">
<div class="col-3">
<div class="list-group">
<a
*ngFor="let c of categories$ | async"
routerLink="/"
[queryParams]="{category: c.$key}"
class="list-group-item list-group-item-action"
[class.active]="category===c.$key">
{{c.name}}
</a>
</div>
</div>
<div class="col">
<div class="row">
<ng-container *ngFor="let p of filteredProducts; let i =index">
<div class="col">
<div class="card" style="width: 15rem;">
<img src="{{p.imageURL}}">
<div class="card-body">
<h5 class="card-title">{{p.title}}</h5>
<p class="card-text">{{p.price | currency: 'EUR': true}}</p>
Add to cart
</div>
</div>
</div>
<div></div>
</ng-container>
</div>
</div>
</div>
TS class:
products:Product[]=[];
filteredProducts: Product[]=[];
category: string;
categories$;
constructor(
private productService: ProductService,
private categoryService: CategoryService,
private route: ActivatedRoute) {
this.categories$=this.categoryService.getCategories();
this.productService.getAll().subscribe(products =>this.products=products)
this.route.queryParamMap.subscribe(params =>{
this.category = params.get('category');
this.filteredProducts = (this.category) ?
this.products.filter(p=>p.category===this.category) :
this.products;
});
}
The service retrives data correcly, but when I log the filtered array, I get nothing...Can someone give me a hand?
EDIT:
your attempting to set your array before you retrieve the products. subscribe is an asynchronous operation so it doesn't execute in the order it's started, but rather in the order the results arrive, and queryParams is a type of observable that emits immediately, so that subscribe is executing BEFORE the products arrive, instead, use observable combineLatest and the map operator and the async pipe:
filteredProducts$: Observable<Product[]>;
....
const category$ = this.route.queryParamMap.pipe(map(params => params.get('category')));
this.filteredProducts$ = combineLatest(this.productService.getAll(), // combine the streams
category$)
.pipe(
tap(([products, category])=> console.log(products, category)), // this is how you log in a stream
map(([products, category]) => // you'll have the latest value from both
(category) ? // run your filter
products.filter(p => p.category.toLowerCase() === category.toLowerCase()) :
products),
tap(filteredProducts => console.log(filteredProducts)) // this is how you log in a stream
);
then in your template just use the async pipe like you did with categories$
<ng-container *ngFor="let p of filteredProducts$ | async; let i =index">
an Observable is JUST a definition of how to handle a stream of data. logging things outside of that stream will not show you the values inside of that stream. the tap operator exists to allow you to log things inside of the stream

Problem with an angular filter of objects without using routes (Angular TS)

I need some help about the code: I have to make a filter for a list of objects and I have to use the observables (the exercise only includes the front end part) and the objects are in a database.
with the code written as soon as I insert a letter in the search bar, the array is emptied and only the last letter remains (for example insert C and after I insert E, in the filter only the E remains)
in TS:
Search(name:any):void{
this.arraycopy=this.mylist
})
this.arraycopy=this.mylist.filter(res =>{
return res.description.includes(name.key) ;
})
}
IN HTML:
<div class="row">
<div class="col-2" *ngFor="let object of arraycopy">
<div class="card">
<div class="card-block">
<p class="card-text">
<a class="breadcrumbLabelStyle" href="{{list.listCode}}" title="access to {{list.description}}">{{list.description}}
</a>
</p>
</div>
</div>
</div>
</div>
Are you sure you're updating your Observable with the full search-bar input and not just the last key pressed?
You are probably updating it based on the keypress event which returns the last key pressed.
Update on Answer:
Try this:
Search-bar:
<input type="text" [ngModel]="searchInput" (keyup)="Search()">
In TS:
public searchTerm = new BehaviorSubject('');
public searchInput: string;
constructor() {
this.searchTerm.subscribe((text: string) => {
this.arraycopy = this.mylist.filter(res => {
return res.description.includes(text);
});
});
}
public Search(): void {
this.searchTerm.next(this.searchInput);
}
This should work, but with this you're not using Observables so good.

ReactJS: Filter rendering of a list by whole names only?

I am currently rendering a list of data returned from an API using the map() function as follows:
renderLocation() {
return this.props.locations.map(location => {
return (
<div key={location.id}>
<div className="location">
<h1>
{location.name}
{location.airport_code}
</h1>
<div className="location-secondary-info">
<span>
<i className="material-icons">airplanemode_active</i>
{location.description}
</span>
</div>
</div>
</div>
);
});
}
I now want to filter the rendering, so that the only locations that are rendered are those that have a correct name field value. My API data looks like this:
I only want locations to be rendered if the locations.name is an actual valid city name.
So for instance, a location with a name of "Chicago O'Hare" would be a valid city name, and should be displayed. A location with a name of "Chicago O'Hare A5C" however, should not be rendered seeing it has the A5C at the end which makes it invalid.
One approach might be to use a regular expression to filter locations based on the presence of an alphanumeric sub-string suffix on a location's name field via the following:
const filteredLocations = this.props.locations.filter(location => {
return !location.name.match(/[A-Z0-9]+$/)
});
The above logic basically says:
"filter all locations where the location's name doesn't have an alphanumeric word at the end of it".
Integrating this into your renderLocation() function could be achieved via:
renderLocation() {
/* Filter locations with name that doesn't have alphanumeric suffix word */
const filteredLocations = this.props.locations.filter(location => {
return !location.name.match(/[A-Z0-9]+$/)
});
/* Render only the filtered location with name Chicago O'Hare */
return filteredLocations.map(location => {
return (
<div key={location.id}>
<div className="location">
<h1>
{location.name}
{location.airport_code}
</h1>
<div className="location-secondary-info">
<span>
<i className="material-icons">airplanemode_active</i>
{location.description}
</span>
</div>
</div>
</div>
);
});
}
Hope that helps

How to search strings inside Array of arrays using eloquent

So I have a databse column where the content is an Array like this:
[{"tag_name":"example1"},{"tag_name":"example2"}, {"tag_name":"example3"}]
What I am trying to do is to retrieve videos with a certain tag. All the videopages have specific tags, and when a user clicks one of those tags, it is redirected to a view where similar videos with the same tag will be displayed.
Right now I have the following controller:
public function search($tag){
$tag = urldecode($tag);
$videos = Video::where('tags', 'LIKE', $tag)->paginate(12);
$settings = Detail::find(1);
$ads = Ad::find(1);
return view('search', ['videos' => $videos, 'settings' => $settings, 'ads' => $ads]);
}
And I have the following view (search.blade.php):
#foreach($videos as $video)
<div class="col-lg-4 col-xs-12">
<div class="row justify-content-center">
<img class="articleImg" src="{{$video->imgurl}}">
</div>
<div>
<p class="float-left">{{$title = substr($video->title, 0, 30) . " ..."}}</p>
<small class="duration float-right">{{$video->duration}}</small>
<div class="progress float-right">
<div class="progress-bar bg-success" role="progressbar" style="width: {{$video->rating}}%" aria-valuenow="{{$video->rating}}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
#endforeach
The problem is that right now, no videos are shown in my view, even tough i get no errors at all. Is it because the columns has an array of arrays?
I assume it's because your controller is returning 0 videos because tag never match.
You are using LIKE statement without escaping your tag variables with %, so you are looking to match something that is exactly like tag, and because you have an array of tags as a column that will never happen.
One solution you could implement is changing your tag to something like this:
public function search($tag){
$tag = urldecode($tag);
$videos = Video::where('tags', 'LIKE', '%'.$tag.'%')->paginate(12);
$settings = Detail::find(1);
$ads = Ad::find(1);
return view('search', ['videos' => $videos, 'settings' => $settings, 'ads' => $ads]);
}
Here you can read more about the LIKE operator :D

view is not being updated after updating object from server call angular 4

I have declare a Array of object in angular 4 like this
public onlinUsers;
I Used this like here
<div class="row" >
<h2>Online users</h2>
{{onlinUsers}}
<div *ngFor="let i of onlinUsers">
<a (click)="openPrivate(i.name)">{{i.name}}</a>
</div>
</div>
and updating it here like this
ngOnInit() {
this.socket.on('onlineUsers',function(data){
this.onlinUsers=data.data
console.log( this.onlinUsers)
})
}
console.log working fine
Why my html is not being rendered . please help
this.socket.on('onlineUsers',function(data){
should be
this.socket.on('onlineUsers', (data) => {
otherwise this won't work as you expect inside the function.
Search for arrow functions for more details.

Resources