Undefined array key "video" - laravel-livewire

create component
<?php
namespace App\Http\Livewire\Teacher\Lesson;
use App\Models\Course;
use App\Models\Lesson;
use Illuminate\Support\Facades\Lang;
use Livewire\Component;
use Livewire\WithFileUploads;
class Create extends Component
{
use WithFileUploads;
public $new_row;
public $authUser;
protected $listeners = ['store'];
public function updatedNewRowImage()
{
$this->validate([
'new_row.video' => 'required|file|max:3000|mimes:mp4',
]);
}
public function mount() {
$this->authUser = \Auth::user();
}
public function rules()
{
return [
'new_row.name.ar' => "required|min:3",
'new_row.name.en' => "required|min:3",
'new_row.content.ar' => "required|min:3",
'new_row.content.en' => "required|min:3",
'new_row.course_id' => 'required|exists:courses,id',
'new_row.video' => 'nullable|file',
'new_row.status' => 'required',
'new_row.duration' => 'required|numeric',
];
}
public function store()
{
$this->validate();
$video_name = $this->new_row['video']->store('video/lessons', 'public');
$this->new_row['video'] = basename(parse_url($video_name, PHP_URL_PATH));
$this->new_row['teacher_id'] = $this->authUser['id'];
Lesson::create($this->new_row);
$this->emit('alert', ['type' => 'success', 'message' => Lang::get('message.success_response_message')]);
return redirect()->route('teacher.lessons.index');
}
//
public function render()
{
$courses = Course::all();
return view('livewire.teacher.lesson.create', compact('courses'));
}
}
Lesson Model
<?php
namespace App\Models;
use App\Traits\FilterScopeModelTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class Lesson extends Model
{
use HasFactory, FilterScopeModelTrait,HasTranslations;
public $translatable = ['name','content'];
protected $guarded = [];
protected function video(): Attribute
{
return Attribute::make(
get: fn($value) => ($this->attributes['video'] ?? false) ? asset('storage/videos/lessons/' . $this->attributes['video']) : '',
);
}
}
blade file
<div class="form-group col-md-6 mb-2">
<label class="col-sm-6 col-form-label" for="inputAdsVideo">#lang('teacher.video')</label>
<div class="col-sm-10 col-lg-10 col-md-2">
<input type="file" name="new_row.video" wire:model="new_row.video " id="Video"
class="form-control is-invalid"
>
</div>
#error('new_row.video')
<small class=" text text-danger" role="alert">
<strong>{{ $message }}</strong>
</small>
#enderror
</div>
migration
Schema::create('lessons', function (Blueprint $table) {
$table->id();
$table->json('name')->nullable();
$table->json('content')->nullable();
$table->foreignId('teacher_id')->nullable()->constrained();
$table->foreignId('course_id')->nullable()->constrained();
$table->float('duration')->nullable();
$table->text('video')->nullable();
$table->enum('status',['pending','publish']);
$table->timestamps();
});
crude of lessons to insert data in data base
when i try to insert data in data base this me undefined key
of video
pleas help to solve and try to upload video all data uploaded with me except video

Related

Livewire auto change content html to text wire:id

Component A (Search)
component class:
namespace App\Http\Livewire\Admin\Shared;
use Livewire\Component;
class Search extends Component
{
public $searchString = '';
public function updated()
{
$this->emitUp('searchForm', $this->searchString);
}
public function searchData()
{
$this->emitUp('searchForm', $this->searchString);
}
public function render()
{
return view('livewire.admin.shared.search');
}
}
component view:
<form wire:submit.prevent='searchData' class="d-none d-sm-inline-block">
<div class="input-group">
<input wire:model.lazy='searchString' id="textSearch" name="textSearch" type="text"
class="form-control bg-white border border-primary small" placeholder="Tìm kiếm...">
<div class="input-group-append">
<button class="btn btn-primary" type="submit">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</form>
Component B (List)
component class:
public $searchString = '';
protected $listeners = ['searchForm'];
public function searchForm($searchStringEmit)
{
$this->searchString = $searchStringEmit;
}
public function getListSupplier()
{
$data = Supplier::where('active', true)
->where('name', 'like', '%' . $this->searchString . '%')
->orderByDesc('id')
->paginate(2);
return $data;
}
public function render()
{
return view('livewire.admin.supplier.list', [
'ListSupplier' => $this->getListSupplier()
]);
}
I have problem with blade front-end. After I click button-search, component-search auto change component view show text wire:id<####>, instead of component-search view.
Example image:
enter image description here
It should have been <div wire:id="xxx"> that's how Livewire marks it's components. Make sure you don't have javascript doing some DOM manipulation. Check your template for more information

React Testing Library: UserEvent.type not working

Problem: UserEvent.type is not working. I have a simple test where I get the textbox, which works, but when trying to type in that textbox, the text does not display.
Most of the solutions I have seen to problems similar to this is to await the typing. I tried that and the text still does not display.
Versions:
"jest": "^28.1.3",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "12.1.2",
"#testing-library/user-event": "^14.2.1",
Test:
test('LoginPage should handle events properly', async () => {
render(<LoginPage />)
const textbox = screen.getByRole(/textbox/i)
await userEvent.type(textbox, 'test')
screen.debug(textbox)
})
Output from screen.debug() after firing the typing:
<textarea
placeholder="enter your private key here."
/>
LoginPage Component:
import { useHistory } from 'react-router-dom'
import { useContext, useState, useEffect } from 'react'
import { ABOUT_URL } from '../../config'
import LoadingCover from '../../components/loadingCover/loadingCover'
import LoadingButton from '../../components/loadingButton/loadingButton'
import UserContext from '../../context/User'
const LoginPage = () => {
const history = useHistory()
const [isLoading, setIsLoading] = useState(false)
const [input, setInput] = useState<string>('')
const [errorMsg, setErrorMsg] = useState<string>('')
const [isButtonLoading, setButtonLoading] = useState<boolean>(false)
const userContext = useContext(UserContext)
useEffect(() => {
setErrorMsg('')
}, [input])
const handleInput = (event: any) => {
setInput(event.target.value)
}
const login = async () => {
setButtonLoading(true)
const hasSignedUp = await userContext.login(input)
setButtonLoading(false)
if (!hasSignedUp) {
setErrorMsg('Incorrect private key. Please try again.')
return
}
// need to conditionally get an airdrop if the user signed up but has
// not claimed an airdrop, and it's the same epoch as when they signed
// up
history.push('/')
}
return (
<div className="login-page">
<div className="left-column">
<img
src={require('../../../public/images/unirep-title-white.svg')}
/>
</div>
<div className="right-column">
<div className="close">
<img
id="unirep-icon"
src={require('../../../public/images/unirep-title.svg')}
/>
<img
id="close-icon"
src={require('../../../public/images/close.svg')}
onClick={() => history.push('/')}
/>
</div>
<div className="info">
<div className="title">Welcome back</div>
<p>
To enter the app, please use the private key you got
when you signed up.
</p>
<textarea
placeholder="enter your private key here."
onChange={handleInput}
/>
{errorMsg.length === 0 ? (
<div></div>
) : (
<div className="error">{errorMsg}</div>
)}
<div className="sign-in-btn" onClick={login}>
<LoadingButton
isLoading={isButtonLoading}
name="Sign in"
/>
</div>
<div className="notification">
Lost your private key? Hummm... we can't help you to
recover it, that's a lesson learned for you. Want to
restart to earn rep points?{' '}
<a
target="_blank"
href={`${ABOUT_URL}/alpha-invitation`}
>
Request an invitation code here.
</a>
</div>
<div className="go-to-signup">
Got an invitation code? Join here
</div>
</div>
</div>
{isLoading ? <LoadingCover /> : <div></div>}
</div>
)
}
export default LoginPage
Got the same issue and find a really simple solution on the Testing Library documentation :
Start your test with
const user = userEvent.setup()
then you call userEvent methods directly from user :
await user.type(textbox, 'test')
You have to setup directly on each test, the library recommend to avoid using beforeEach() for this.

Problem getting value for livewire component's public property

I am working on livewire in my project and I encounter a problem.
I have livewire model and blade file as below:
LivewireCounter.php
class LivewireCounter extends Component
{
public $count;
public function render()
{
return view(Constant::LIVEWIRE_COUNTER_BLADE);
}
public function mount($count = 0)
{
$this->count = $count + 1;
}
public function increment()
{
if($this->count >= Constant::LIVEWIRE_COUNTER_MAX)
{
$this->count = Constant::LIVEWIRE_COUNTER_MAX;
} else {
$this->count++;
}
}
public function decrement()
{
if($this->count <= Constant::LIVEWIRE_COUNTER_MIN)
{
$this->count = Constant::LIVEWIRE_COUNTER_MIN;
} else {
$this->count--;
}
}
}
livewire-counter.blade.php
<div>
<div class="flex inline-block relative w-64">
<button class="px-1" wire:click="decrement">-</button>
<h1>{{ $count }}</h1>
<button class="px-1" wire:click="increment">+</button>
</div>
</div>
I have a coupon blade file which uses livewire to track the coupon ordered by user.
coupon-show.blade.php
#extends(Constant::LAYOUTS_APP)
#section(Constant::LAYOUTS_CONTENT)
<div class="container">
<div>
<p class="text-4xl text-extrabold text-gray-900">{{ $CouponSetting->name }}</p>
#livewire('livewire-counter', ['count' => 9])
</div>
{{$count}}
</div>
</div>
#endsection
The problem I am having is I am unable to retrieve the $count value in the coupon-show.blade.php file. I thought the public property of the livewire component should be able to be accessed by blade view?
ErrorException
Undefined variable: count (View: /Applications/MAMP/htdocs/XXX/resources/views/layouts/coupons/coupon-show.blade.php)
Any idea why?

How to render element depends on selected option?

i'm newbie in react js , and i want to have a form with select options
i want that when user click on each option , each option render different elements
class Resepy extends Component {
state = {
Resepy : 'default'
}
render() {
return = (
<div className="Resepy">
<form>
<select id="id_field1" name="field1" onChange={(e) => this.state.Resepy = "Burger"}>
<option value="default">Food type not selected</option>
<option value="burger" onClick={(e) => this.setState({ Resepy: 'Burger' })}>Burger</option>
<option value="pizza" onClick={(e) => this.setState({ Resepy: 'Pizza' })}>Pizza</option>
</select>
<div className="food">
{ this.state.Resepy === "burger" ? <div className="burger"></div> //can return any html
: <div className="default">default</div>
}
<div className="pizza"></div>
<div className="food-detail"></div>
</div>
<button type="submit">Add to tray</button>
</form>
</div>
);
}
}
export default Resepy;
General ternary operator used for more readable code.
Like this:
<form>//can be any element
{ codition == true ? <div>It is true</div> //can return any html
: <div>It is false</div>
}
</form>
Tested, working. Problem was with onClick method option cannot invoke that event.
class Resepy extends React.Component {
constructor(props){
super(props);
this.state = {
selected : 'default'
};
}
setSelected = (event) => {
let select = document.getElementById("id_field1");
this.setState({selected: select.value});
//document.getElementById("test").innerHTML = select.value;
}
render() {
return (
<div className="Resepy">
<h1>Something</h1>
<form>
<select id="id_field1" name="field1" onChange={this.setSelected}>
<option value="default">Food type not selected</option>
<option value="burger">Burger</option>
<option value="pizza">Pizza</option>
</select>
<div id="test"></div>
<div className="food">{
(this.state.selected === "default") ?
<div className="default">Default</div>
: (this.state.selected === "burger") ?
<div className="burger">Burger</div>
: <div className="pizza">Pizza</div>
}</div>
<button type="submit">Add to tray</button>
</form>
</div>
);
}
}
I have a hard time understanding you, but the most likely thing you could be trying to achieve with the following code from your original question:
<div className="burger" Resepy={this.state.Resepy === 'burger'}></div>
is:
<div className="food">
<div className={this.state.Resepy} />
</div>
Working example (but I am using Hooks instead of a class component):
const App = () => {
const [selected, setSelected] = React.useState('default')
const handleChange = (event) => {
setSelected(event.target.value)
}
return (
<div>
<select value={selected} onChange={handleChange}>
<option>default</option>
<option>burger</option>
<option>pizza</option>
</select>
<div className="food">
<div className={selected}>{selected}</div>
</div>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
.default { color: gray; }
.burger { color: orange; }
.pizza { color: red; }
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Now i want to render html elements depends on values , i tried this but it shows just [Object Object]
setSelected = (event) => {
let select = document.getElementById("id_field1");
document.getElementById("food").innerHTML =
select.value == "default" ?
<div className="default">Default</div>
: select.value == "Burger" ?
<div className="burger">Burger</div>
: <div className="pizza">Pizza</div>
}

Vue.js unit test w avoriaz , how to test submit event

I am trying to test a form submit.. it seems that trigger is not appropriate
1) calls store action login when the form is submitted
LoginPage.vue
TypeError: wrapper.find(...).trigger is not a function
at Context.<anonymous> (webpack:///test/unit/specs/pages/LoginPage.spec.js:35:28 <- index.js:50826:29)
my vue component to be tested
LoginPage.vue
<template>
<div class="container">
<div class="login-page">
<h1 class="title">Login to existing account</h1>
<form #submit.prevent="submit()" class="form form--login grid">
<div class="row">
<label for="login__email">Email</label>
<input type="text" id="login__email" class="input--block" v-model="email" v-on:keyup="clearErrorMessage" />
</div>
<div class="row">
<label for="login__password">Password</label>
<input type="password" id="login__password" class="input--block" v-model="password" v-on:keyup="clearErrorMessage" />
</div><!-- /.row -->
<div class="row">
<label></label>
<button id="submit" type="submit">Login</button>
</div><!-- /.row -->
<div v-show='hasError' class="row">
<label></label>
<p class="error">Invalid credentials</p>
</div>
</form>
</div><!-- /.login-page -->
</div>
</template>
<script>
import store from '#/vuex/store'
import { mapActions } from 'vuex'
import _ from 'underscore'
export default {
name: 'loginPage',
data () {
return {
email: 'john.doe#domain.com',
password: 'john123',
hasError: false
}
},
methods: _.extend({}, mapActions(['login']), {
clearErrorMessage () {
this.hasError = false
},
submit () {
return this.login({user: { email: this.email, password: this.password }})
.then((logged) => {
if (logged) {
this.$router.push('shoppinglists')
} else {
this.hasError = true
}
})
}
}),
store
}
</script>
LoginPage.spec.js
import LoginPage from '#/pages/LoginPage'
import Vue from 'vue'
import Vuex from 'vuex'
import sinon from 'sinon'
import { mount } from 'avoriaz'
Vue.use(Vuex)
describe('LoginPage.vue', () => {
let actions
let getters
let store
beforeEach(() => {
actions = {
login: sinon.stub()
}
getters = {
isAuthenticated: () => {
state => state.isAuthenticated
}
}
store = new Vuex.Store({
actions,
getters,
state: {
isAuthenticated: false,
currentUserId: ''
}
})
})
it('calls store action login when the form is submitted', (done) => {
const wrapper = mount(LoginPage, { store })
wrapper.find('#submit').trigger('submit')
wrapper.vm.$nextTick(() => {
expect(actions.login.calledOnce).to.equal(true)
done()
})
})
})
Should be trigger 'click' on the form tag !
it('calls store action login when the form is submitted', (done) => {
const wrapper = mount(LoginPage, { store })
const form = wrapper.find('form')[0]
form.trigger('submit')
wrapper.vm.$nextTick(() => {
expect(actions.login.calledOnce).to.equal(true)
done()
})
})