Live-wire - real time chat not responding correctly - javascript

I'm trying live-wire to see how to implement it in my upcoming project. The idea is a simple chat ( user enters a body of text and click send then the message will be at the bottom of the chat)
So far everything works fine till I hit the click send button.
Here is picture before I click on send
and here is what happens after I click send
I feel like the issue is in this part of code where I send the message to the live-wire blade
#foreach ($messages as $message)
#if($message->isYou())
<livewire:conversations.conversation-message-own :message="$message" :key="$message->id" />
#else
<livewire:conversations.conversation-message :message="$message" :key="$message->id" />
#endif
#endforeach
here is the component
public $body= "";
public $conversation;
public function mount(Conversation $conversation)
{
$this->conversation = $conversation;
}
public function reply()
{
$this->validate([
'body' => 'required',
]);
$message = $this->conversation->messages()->create([
'user_id' => user()->id,
'body' => $this->body,
]);
$this->emit('message.created',$message->id);
$this->body = "";
}
public function render()
{
return view('livewire.conversations.conversation-reply');
}
}
last is listening to the event component:
class ConversationMessages extends Component
{
public $messages;
public function mount(Collection $messages)
{
$this->messages = $messages;
}
public function render()
{
return view('livewire.conversations.conversation-messages');
}
protected function getListeners()
{
return [
'message.created' => 'prependMessage',
];
}
public function prependMessage($id)
{
$this->messages->prepend(Message::find($id));
}
}
the issue in the inspect log is
Uncaught (in promise) TypeError: Cannot read property 'data' of null
but I think it's not related to the chats data!
Thanks in advance

The problem is in the keys passed to the conversation-messages components. Livewire breaks trying to render these components, even if separated with ifs. You will need to generate different keys, like a string 'message-own-' . $message->id and 'message-'. $message->id . I tested your code with rand() data:
#foreach ($messages as $message)
#if($message->isOwn())
<livewire:conversations.conversation-message-own :message="$message" :key="rand() * $message->id" />
#else
<livewire:conversations.conversation-message :message="$message" :key="rand() * $message->id" />
#endif
#endforeach

Related

Want to call function in child component from parent component

I have one component with name Company and from that component I am opening one popup modal, below is code for that.
Now in that popup modal user is uploading file and submit it, and then I am calling API.
Once API return success response then I want to call one function from Company component in that popup modal component.
html code
<div class="fileUploadButton">
<button color="primary" (click)="openUploadDocumentDialog()">
Add Other Documents
</button>
</div>
ts file code
public openUploadDocumentDialog() : void {
const dialogRef = this.dialog.open(UploadDocumentDialogComponent, {
width: '50vw',
panelClass: ['documentsUploadDialog', 'ceqUserDialog'],
data: {
companyid: this.route.snapshot.params['company_guid']
}
});
}
Now in this upload document dialog component user is uploading file, so once user upload file then click on Save then I am calling API.
It is successfully calling it. What I want is once this API get called successfully and returned response then I want to call method from Company component.
Upload-document-dialog.ts file
public uploadFileHandler(): void {
this.apiService.uploadDocumentFile(this.uploadedFile)
.subscribe({
next: (event) => {
if (event.data) {
**// here I want to call function from Parent company dialog.**
this.dialogRef.close(event.data);
}
},
error: (err) => {
this.snackBar.open('Connect error! Please try again!', 'Ok', {
duration: 2000,
});
},
});
}
This is the way I would go about solving the problem. I think in general it is 'bad practice' to call a function from the parent from the dialog box. So to get around this we would do the following.
Subscribe to dialogRef.afterClosed() call.
For example you could do something like this on the Company component
.html
<div class="fileUploadButton">
<button color="primary" (click)="openUploadDocumentDialog()">
Add Other Documents
</button>
</div>
.ts
public openUploadDocumentDialog() : void {
const dialogRef = this.dialog.open(UploadDocumentDialogComponent, {
width: '50vw',
panelClass: ['documentsUploadDialog', 'ceqUserDialog'],
data: {
companyid: this.route.snapshot.params['company_guid']
}
});
dialogRef.afterClosed().subscribe(response=> {
// 'response' will be 'event.data' from this.dialogRef.close(event.data)
})
}

Array to String conversion Error in Laravel vue.js

I have already posted before with no real replies so I am trying again. I am trying to build a simple table to read data from a mongodb database which will be retrieved by using a query builder in laravel the data needs to be displayed with a vue component but when I try to load up the page an error message comes up:
The full error message if needed : Edit now the error has been fixed the new problem is that no data is being displayed just the titles of the table
ErrorException
Array to string conversion
at vendor/laravel/framework/src/Illuminate/Routing/ResourceRegistrar.php:416
412▕ protected function getResourceAction($resource, $controller, $method, $options)
413▕ {
414▕ $name = $this->getResourceRouteName($resource, $method, $options);
415▕
➜ 416▕ $action = ['as' => $name, 'uses' => $controller.'#'.$method];
417▕
418▕ if (isset($options['middleware'])) {
419▕ $action['middleware'] = $options['middleware'];
420▕ }
+14 vendor frames
15 routes/api.php:20
Illuminate\Support\Facades\Facade::__callStatic()
+3 vendor frames
19 routes/api.php:21
Illuminate\Routing\RouteRegistrar::group()
Here is the code I have used if you wish to replicate:
api.php route:
Route::middleware('api')->group(function () {
Route::resource('/home', [ProductController::class,'home']);
});
web.php route:
Route::get('{any}', function () {
return view('home');
})->where('any', '.*');
PostController Home method:
public function home() {
$posts = Post::paginate(4);
return response()->json($posts);
}
Home component:
<template>
<div>
<table>
<tr>
<td>Id</td>
<td>Title</td>
<td>Status</td>
</tr>
<tr v-for="El in results" v-bind:key="El.id" >
<td>{{El.id}}</td>
<td>{{El.STATUS}}</td>
</tr>
</table>
</div>
</template>
<script>
export default{
data() {
return {
results: []
};
},
methods: {
fetch() {
axios.get('/api/home')
.then(response => this.results = response.data)
.catch(error => console.log(error));
}
}
}
</script>
Home.blade.php:
#extends('layouts.app')
#section('content')
<div class="container" id="app">
<home-component></home-component>
</div>
#endsection
The code seems to be working fine the problem is starting at the api route handler but the why and how to solve it are beyond me. SO, Any and all help and suggestions are appreciated.
Edit: the original question was about an error which has since been removed but replaced with a new problem which is mentioned above.
Your issue is that you are providing too many arguments to the Route::resource(...) method.
The purpose of the Route::resource method is to define multiple routes and their corresponding controller actions according to the resourceful controller pattern.
In your case, you definitely are not using resourceful controllers since you have defined your controller action as public function home(). To fix this, you can simply define the Route::get(...) for the endpoint you are calling in your vue component.
Route::middleware('api')->group(function () {
Route::get('/home', [ProductController::class, 'home']);
});

How to show the status of friendship in relation to an authorized user in laravel?

I am learning react native and using laravel as backend. How to write an action in a laravel to display a list of users (for searching by users on the frontend) to show status everyone's friendship is for an authorized user "Pending", "Confirmed", "Blocked" to respectively show the desired button for example "Add friend", "Accept friend request", "Remove from friends" and "Block"? My code:
Friendship table migration:
Schema::create('friendships', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('first_user')->index();
$table->unsignedBigInteger('second_user')->index();
$table->unsignedBigInteger('acted_user')->index();
$table->enum('status', ['pending', 'confirmed', 'blocked']);
$table->timestamps();
});
User model:
//======================== functions to get friends attribute =========================
// friendship that this user started
protected function friendsOfThisUser()
{
return $this->belongsToMany(User::class, 'friendships', 'first_user', 'second_user')
->withPivot('status')
->wherePivot('status', 'confirmed');
}
// friendship that this user was asked for
protected function thisUserFriendOf()
{
return $this->belongsToMany(User::class, 'friendships', 'second_user', 'first_user')
->withPivot('status')
->wherePivot('status', 'confirmed');
}
// accessor allowing you call $user->friends
public function getFriendsAttribute()
{
if ( ! array_key_exists('friends', $this->relations)) $this->loadFriends();
return $this->getRelation('friends');
}
protected function loadFriends()
{
if ( ! array_key_exists('friends', $this->relations)) {
$friends = $this->mergeFriends();
$this->setRelation('friends', $friends);
}
}
protected function mergeFriends()
{
if($temp = $this->friendsOfThisUser) {
return $temp->merge($this->thisUserFriendOf);
} else {
return $this->thisUserFriendOf;
}
}
//======================== end functions to get friends attribute =========================
//====================== functions to get blocked_friends attribute ============================
// friendship that this user started but now blocked
protected function friendsOfThisUserBlocked()
{
return $this->belongsToMany(User::class, 'friendships', 'first_user', 'second_user')
->withPivot('status', 'acted_user')
->wherePivot('status', 'blocked')
->wherePivot('acted_user', 'first_user');
}
// friendship that this user was asked for but now blocked
protected function thisUserFriendOfBlocked()
{
return $this->belongsToMany(User::class, 'friendships', 'second_user', 'first_user')
->withPivot('status', 'acted_user')
->wherePivot('status', 'blocked')
->wherePivot('acted_user', 'second_user');
}
// accessor allowing you call $user->blocked_friends
public function getBlockedFriendsAttribute()
{
if ( ! array_key_exists('blocked_friends', $this->relations)) $this->loadBlockedFriends();
return $this->getRelation('blocked_friends');
}
protected function loadBlockedFriends()
{
if ( ! array_key_exists('blocked_friends', $this->relations)) {
$friends = $this->mergeBlockedFriends();
$this->setRelation('blocked_friends', $friends);
}
}
protected function mergeBlockedFriends()
{
if($temp = $this->friendsOfThisUserBlocked) {
return $temp->merge($this->thisUserFriendOfBlocked);
} else {
return $this->thisUserFriendOfBlocked;
}
}
// ======================================= end functions to get block_friends attribute =========
public function friend_requests()
{
return $this->hasMany(Friendship::class, 'second_user')
->where('status', 'pending');
}
Function in controller:
public function show(Request $request)
{
$user = auth()->user();
$users = User::where('id', '!=', $user->id)->get();
return UserInfoResource::collection($users);
}
I tried to do something like this in the resource:
public function toArray($request)
{
return [
"id" => $this->id,
"uuid" => $this->uuid,
"first_name" => $this->first_name,
"last_name" => $this->last_name,
"avatar" => asset( 'storage/' . $this->avatar ),
"friendship" => $this->friends->only([auth()->user()->id])->first(),
// "friendship" => $this->pivot,
];
}
But ->friends only shows "confirmed" friendships, how can I track the rest of the statuses?
Since you have set:
->wherePivot('status', 'confirmed');
you will only get the friends with that specific status.
There is a wherePivotIn()-method that allows you to add multiple values to match for.
Changing it to something like:
->wherePivotIn('status', ['confirmed', 'anotherStatus', ...etc...]);
should give you the friends with the other statuses as well.
You can read more in the manual about that method (and others)

Asynchronous method doesn't work the first time

I'm new in Firebase. I'm using Firestore database and Ionic, I have this problem with an asynchronous call and I can't solve it. Basically in the item variable goes the data that I have saved in the firestore database. But when I want to show them, through a button, in a new html page a strange thing happens, in the url the passed parameter appears and disappears immediately and nothing works anymore. I had a similar problem in the past that I solved using the angular pipe "async" , but in this case it doesn't even work.
In detail, I have a list of items in a component:
ngOnInit() {
this.itemService.getItemsList().subscribe((res)=>{
this.Tasks = res.map((t) => {
return {
id: t.payload.doc.id,
...t.payload.doc.data() as TODO
};
})
});
}
and in item.service.ts I have defined the function:
constructor(
private db: AngularFireDatabase,
private ngFirestore: AngularFirestore,
private router: Router
) { }
getItemsList() {
return this.ngFirestore.collection('items').snapshotChanges();
}
getItem(id: string) {
return this.ngFirestore.collection('items').doc(id).valueChanges();
}
For each item I have a button to show the detail:
<ion-card *ngFor="let item of Tasks" lines="full">
....
<ion-button routerLinkActive="tab-selected" [routerLink]="['/tabs/item/',item.id]" fill="outline" slot="end">View</ion-button>
In component itemsDescription.ts I have:
ngOnInit() {
this.route.params.subscribe(params => {
this.id = params['id'];
});
this.itemService.getItem(this.id).subscribe((data)=>{
this.item=data;
});
}
Finally in html page:
<ion-card-header>
<ion-card-title>{{item.id}}</ion-card-title>
</ion-card-header>
<ion-icon name="pin" slot="start"></ion-icon>
<ion-label>{{item.Scadenza.toDate() | date:'dd/MM/yy'}}</ion-label>
<ion-card-content>{{item.Descrizione}}</ion-card-content>
The Scadenza and Descrizione information are shown, instead id is not. Also the url should be tabs/items/:id but when I click on the button to show the item information, the passed parameter immediately disappears and only tabs/items is displayed. If I remove the data into {{}}, the parameter from the url doesn't disappear
SOLVED
I followed this guide https://forum.ionicframework.com/t/async-data-to-child-page-with-ionic5/184197. So putting ? , for example {{item?.id}} now everything works correctly
Your nested code order not right. You will get the value of id after subscription.
Check this Code:
ngOnInit() {
this.route.params.subscribe(params => {
this.id = params['id'];
this.profileService.getItem(this.id).subscribe((data)=>{
this.item=data;
});
});
}

How to put data from a controller into a specfic div element in a view

How can I load data i.e $mytweets into a specific div within a specific template/view i.e footer.php?
I have twitteruserfeed.php as my Controller for getting the tweets, but I don't know how to present it within an already existing.
HTML:
<div id="fresh-tweetfeed"> $mytweets GOES HERE </div>
PHP:
class TwitterUserFeed extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function getTweets()
{
$params = array(
'userName' => 'RowlandBiznez',
'consumerKey' => 'hgfhhgffhg',
'consumerSecret' => 'hhffhfghfhf',
'accessToken' => 'hfhhhfhhf',
'accessTokenSecret' => 'hfhfhfhfhhfhfh',
'tweetLimit' => 5 // the no of tweets to be displayed
);
$this->load->library('twitter', $params);
$tweets = $this->twitter->getHomeTimeLine();
$this->load->helper('tweet_helper');
$mytweets = getTweetsHTML($tweets);
echo $mytweets;
}
}
I also have a helper file tweet_helper.php. Help me out with this presentation.
Solution #1:
If the tweets must be displayed on every page, extend the CI_Controller (create MY_Controller.php file inside application/core folder) and fetch/store the tweets on a property:
class MY_Controller extends CI_Controller
{
public $tweets = '';
public function __construct()
{
// Execute CI_Controller Constructor
parent::__construct();
// Store the tweets
$this->tweets = $this->getTweets();
}
public function getTweets()
{
$params = array(
'userName' => 'RowlandBiznez',
'consumerKey' => 'hgfhhgffhg',
'consumerSecret' => 'hhffhfghfhf',
'accessToken' => 'hfhhhfhhf',
'accessTokenSecret' => 'hfhfhfhfhhfhfh',
'tweetLimit' => 5 // the no of tweets to be displayed
);
$this->load->library('twitter', $params);
$tweets = $this->twitter->getHomeTimeLine();
$this->load->helper('tweet_helper');
$mytweets = getTweetsHTML($tweets);
return $mytweets;
}
}
Then in each controller use that property when you load a view:
$this->load->view('path/to/view', array('tweets', $this->tweets));
Solution #2:
You could also load the tweets by sending a XHR request from the client to Controller/Method (after serving the page), then insert the response into the page by Javascript.
Here is a jQuery sample:
$.ajax({
url : <?php echo base_url('controller/method'); ?>,
type : 'GET',
success : function (result) {
// Insert the result into a container
$('#fresh-tweetfeed').append(result);
}
});

Categories

Resources