Completly skip rendering of component - laravel-livewire

How can I set the component to only show if there are videos?
<?php
namespace App\Http\Livewire;
use App\Models\Video;
use Livewire\Component;
class VideosBrowse extends Component
{
// Computed Property
public function getVideosProperty()
{
return Video::latest()->paginate(10);
}
public function output($errors = null)
{
if (!$this->videos || $this->videos->isEmpty()) {
$this->skipRender();
}
return parent::output($errors);
}
public function render()
{
return view('livewire.videos.browse');
}
}
View:
<div id="videos-browse">
#if ($this->videos && $this->videos->isNotEmpty())
Videos
#endif
</div>

You have to run skipRender() on render
public function render() {
if (!$this->videos || $this->videos->isEmpty()) {
$this->skipRender();
}
return view('livewire.videos.browse');
}

Related

Why listing of items is empty in calling method of the component?

with livewire 2 I have listing of items ($itemDataRows var) and I need for any item show checkbox ($selectedItems var) and
"Select all" button and clicking on this button all items must be selected. I do :
class CrudItems extends Component
{
private $itemDataRows = [];
public $selectedItems = [];
...
public function render()
{
...
$this->itemDataRows = Item
::orderBy('created_at', 'desc')
...
->paginate($backend_per_page);
return view('livewire.admin.items.crud-items', [
'itemDataRows' => $this->itemDataRows,
'item_rows_count' => $this->item_rows_count
])->layout('layouts.admin');
}
}
public function calcSelectedItemsCount()
{
$ret= 0;
foreach( $this->selectedItems as $next_key=>$next_value ) {
if($next_value) {
$ret++;
}
}
return $ret;
}
public function selectAllItems()
{
$this->selectedItems= [];
\Log::info( dump($this->itemDataRows, ' -0 $this->itemDataRows selectAllItems::') );
// INL OG FILE_I SEE THAT ARRAY ABOVE IS EMPTY!!!
foreach( $this->itemDataRows as $nextItemDataRow ) {
$this->selectedItems[$nextItemDataRow->id] = true;
\Log::info( dump($this->selectedItems, ' -$this->selectedItems INSIDE selectAllItems::') );
}
\Log::info( dump($this->selectedItems, ' -$this->selectedItems selectAllItems::') );
}
and in template :
$selectedItems::{{ var_dump($selectedItems) }}<hr>
$itemDataRows::{{ $itemDataRows }}
/* $selectedItems is filled ok when I click on checkboxes , but $itemDataRows shows empty var, though I filled items listing below */
#foreach ($itemDataRows as $item)
<tr>
<td class=" whitespace-nowrap ">
<x-jet-checkbox id="is_reopen" type="checkbox" class="editor_checkbox_field ml-4" title="On saving editor will be opened"
wire:model="selectedItems.{{ $item->id }}"/>
</td>
Is something wrong with definition of $itemDataRows ? Why $itemDataRows is empty in selectAllItems method, but on my template all items are visible ok....
Thanks in advance!
In Livewire you can pass the data via the class variables. And in the mount function you can fill the variable. For Example.
Important Note: The Class Vars must be public!
public $selectedItems = [];
public function mount(): void
{
$this->selectedItems = ['data' => 'Hello World'];
}
public function render()
{
return view('livewire.admin.items.crud-items')->layout('layouts.admin');
}
Update
This must have something to do with the Livewire Lifecyle. Every Livewire component goes through a lifecycle. Lifecycle hooks allow you to run code at any stage of the component's lifecycle or before updating certain properties. In your case, use the mount hook.
You initialise the variable itemDataRows in the render function. A request then calls the method selectAllItems. There you have to initialise itemDataRows again, because the state is no longer there during render or mount.
Solution: create a method getItemDataRows()
private getItemDataRows()
{
$this->itemDataRows => Item::orderBy('created_at', 'desc')
...
->paginate($backend_per_page);
}
then you can call those in the render method and in the selectAllItems method too.
public function selectAllItems()
{
$this->selectedItems= [];
$this->itemDataRows => $this->getItemDataRows();
...
// your code
}

Testing Laravel Livewire sorting component

I'm trying to test a sort by call for a table, The sort by works in practice but I cannot generate a failing test, my test always passes so I'm not testing it correctly.
Steps to Reproduce:
This is the test:
Livewire::test(Roles::class)
->call('sortBy', 'blah')
->assertSet('sortField', 'blah')
->call('roles')
->assertStatus(200);
the param blah should match a database column, I don't have a column called blah so should fail, but it passes.
the component:
class Roles extends Component
{
use WithPagination;
public $paginate;
public $query;
public $sortField = 'name';
public $sortAsc = true;
protected $queryString = ['query'];
public function render()
{
abort_if_cannot('view_roles');
return view('livewire.roles.roles');
}
public function builder()
{
return Role::orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc');
}
public function sortBy($field)
{
if ($this->sortField === $field) {
$this->sortAsc = ! $this->sortAsc;
} else {
$this->sortAsc = true;
}
$this->sortField = $field;
}
public function roles()
{
$query = $this->builder();
if ($this->query) {
$query->where('name', 'like', '%'.$this->query.'%');
}
return $query->paginate($this->paginate);
}
public function deleteRole($id): void
{
abort_if_cannot('delete_roles');
$this->builder()->findOrFail($id)->delete();
$this->dispatchBrowserEvent('close-modal');
}
}
Are you using the latest version of Livewire: v2.3.6
If I attempt to run:
wire:click.prevent="sortBy('blah')
Then I do get an SQL error as expected.
Anyone know how I can update my test to actually see there's an error.

Mocking out NavParams in Ionic3 gives back Property Data is missing in type typeOf NavParams

export class NavParamsMock {
static returnParam = null;
public get(key): any {
if (NavParamsMock.returnParam) {
return NavParamsMock.returnParam
}
return 'default';
}
static setParams(value){
NavParamsMock.returnParam = value;
}
}
It's not working.
As the error notes the data is missing from your class so it fails.
If you don't care and want to avoid these kind of errors then extend your class.
export class NavParamsMock extends NavParams
This will fill in the missing properties.
If you don't want to extend the full class you can just the data property as the error says
export class NavParamsMock {
static returnParam = null;
get data(){ return NavParamsMock.returnParam; }
set data(params) { NavParamsMock.returnParam = params; }
public get(key): any {
if (NavParamsMock.returnParam) {
return NavParamsMock.returnParam
}
return 'default';
}
static setParams(value){
NavParamsMock.returnParam = value;
}
}

Upgrading Spock unit tests from Grails 1.3.9 to Grails 2.3.9. But edit() test is failing

I am updating unit tests in a Grails project. We were originally using version 1.3.9 and now we are updating to version 2.3.9. I am using Spock.
I keep getting this error:
results:
junit.framework.AssertionFailedError: Condition not satisfied:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
| | | |
| null false John
com.xxxxxx.xxxxx.FilterCategoryController#20574000
Here is the controller code:
#Secured(["hasAnyRole('CM_ADMIN')"])
def edit() {
def filterCategoryInstance = FilterCategory.get(params.id)
if (!filterCategoryInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'dpFilterCategory.label', default: 'FilterCategory'), params.id])}"
redirect(action: "list")
}
else {
return [filterCategoryInstance: filterCategoryInstance]
}
}
and here is the test code:
#Mock([FilterCategory, FilterCategoryTag])
#TestFor(FilterCategoryController)
#TestMixin(DomainClassUnitTestMixin)
class FilterCategoryControllerSpec extends ExtendedControllerSpec {
def 'edit action: existing FilterCategory'() {
setup:
mockI18N(FilterCategoryController)
params.id = filterCategoryInstance.id
expect:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
where:
tag = new FilterCategoryTag(name: 'tag1')
filterCategoryInstance = new FilterCategory(name: "John",
submissionText:"John", sortOrder:0, 'filterCategoryTags': [tag])
}
And here is the ExtendedControllerSpec code. I hope I have included enough code:
I have looked at the following web pages for guidance:
#Mixin(MetaClassMixin)
class ExtendedControllerSpec extends Specification {
def props
protected void setup() {
//super.setup()
props = new Properties()
File file = new File("grails-app/i18n/messages.properties")
if (file.exists()) {
def stream = new FileInputStream(file)
props.load stream
stream.close()
}
mockI18N(controller)
}
def mockI18N = { controller ->
controller.metaClass.message = { Map map ->
if (!map.code)
return ""
if (map.args) {
def formatter = new MessageFormat("")
if (props.getProperty(map.code)) {
formatter.applyPattern props.getProperty(map.code)
}
return formatter.format(map.args.toArray())
} else {
if (props && props.hasProperty(map.code)) {
return props.getProperty(map.code)
} else {
return map.code
}
}
}
}
/**
* add dynamic methods in test setup.
*/
protected void addDynamicMethods() {
registerMetaClass(String)
String.metaClass.mixin StringUtils
}
protected GrailsUser mockGrailsUser() {
return Mock(GrailsUser)
}
...
/**
* must call AFTER mockDpSercurityService
*/
protected void setHasRoleTrue() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return true}
}
}
protected void setHasRoleFalse() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return false}
}
}
protected void mockUserService() {
controller.dpUserService = new MockFor(UserService)
}
}
http://sanjaykanwar.blogspot.com/2012/07/grails-controller-test-with-spock.html
http://naleid.com/blog/2012/05/01/upgrading-to-grails-2-unit-testing
Looks like the if branch gets executed in edit() instead of the else branch because FilterCategory does not get saved and therfore does not get a proper id.

Add coded control to UIMap (Coded UI Test)

I would like to add a handwritten coded control to my UIMap.cs (not UIMap.Designer.cs).
For example, when I record: writing in a texBox, I get the following code in UIMap.Designer.cs:
public class Recorded_Writing_In_forRecordParams
{
public string UIForRecordEditText = "forRecord";
}
public class UIMainWindowWindow : WpfWindow
{
public UIMainWindowWindow()
{
this.SearchProperties[WpfWindow.PropertyNames.Name] = "MainWindow";
this.SearchProperties.Add(new PropertyExpression(WpfWindow.PropertyNames.ClassName, "HwndWrapper", PropertyExpressionOperator.Contains));
this.WindowTitles.Add("MainWindow");
}
public WpfEdit UIForRecordEdit
{
get
{
if ((this.mUIForRecordEdit == null))
{
this.mUIForRecordEdit = new WpfEdit(this);
this.mUIForRecordEdit.SearchProperties[WpfEdit.PropertyNames.AutomationId] = "forRecord";
this.mUIForRecordEdit.WindowTitles.Add("MainWindow");
}
return this.mUIForRecordEdit;
}
}
private WpfEdit mUIForRecordEdit;
}
I want use this control in my CodedUITest. Is there a way to search the TextBox in the UIMap.cs by own coded or to search it in my TestMethod? Which is the best way?
Thanks for the answer, but I solved my problem on my own with the following way:
UIMap.cs
public partial class TestLittleAppUIMap
{
private MyWindow mMyWindow;
public MyWindow MMyWindow
{
get
{
if (this.mMyWindow == null)
{
this.mMyWindow = new MyWindow();
}
return this.mMyWindow;
}
}
}
public class MyWindow : WpfWindow
{
private WpfEdit mWpfEdit;
public MyWindow()
{
this.SearchProperties[WpfWindow.PropertyNames.Name] = "MainWindow";
this.SearchProperties.Add(new PropertyExpression(WpfWindow.PropertyNames.ClassName, "HwndWrapper", PropertyExpressionOperator.Contains));
this.WindowTitles.Add("MainWindow");
}
public WpfEdit MWpfEdit
{
get
{
if ((this.mWpfEdit == null))
{
this.mWpfEdit = new WpfEdit(this);
#region Search Criteria
this.mWpfEdit.SearchProperties[WpfEdit.PropertyNames.AutomationId] = "forOwn";
this.mWpfEdit.WindowTitles.Add("MainWindow");
#endregion
}
return this.mWpfEdit;
}
}
CodedUI Test
[TestMethod]
public void TestLittleAppOwnMap()
{
this.UIMap.MMyWindow.MWpfEdit.DrawHighlight();
Playback.Wait(2500);
}
It is almost a copy of the designer class.
For searching directly in the TestMethod you can go like this:
[TestMethod]
public void TestLittleAppOwn()
{
WpfWindow w = new WpfWindow();
w.SearchProperties[WpfWindow.PropertyNames.Name] = "MainWindow";
w.SearchProperties.Add(new PropertyExpression(WpfWindow.PropertyNames.ClassName, "HwndWrapper", PropertyExpressionOperator.Contains));
w.DrawHighlight();
WpfEdit e = new WpfEdit(w);
e.SearchProperties[WpfEdit.PropertyNames.AutomationId] = "forOwn";
e.SetProperty("Text","myText");
e.DrawHighlight();
Playback.Wait(2500);
}
Where Playback.Wait just wait a short time for showing the Highlight.