Spartacus 4.2 - Type '"before"' is not assignable to type 'OutletPosition' - spartacus-storefront

While trying to customize the navigation slot, we are getting the error
Type '"before"' is not assignable to type 'OutletPosition'.
This is the code we are trying.
Also have tried
[cxOutletPos]=“outletPosition.BEFORE”
Documentation referred for Spartacus 4.2 :
https://sap.github.io/spartacus-docs/outlets/#template-driven-outlets
Result should be something like custom info, followed by navigation bar as shown below:
Also, as the above method didn't work I tried retrieving data through let-model for manipulation.
Array I want to retrieve data from into our component: CategoryNavigationComponent.
But using let-model and Printing model object I can see only "uid" , "typeCode" and "flexType" but not the navigatioNode and Children.
Is there any way to retrieve Navigation bar or Children array data on the screen?

****in TS File:****
settingsSubmenu: any = [];
constructor(public component: CmsComponentData<any> )
{
this.component.data$.forEach(element => {
element.navigationNode.children.forEach(child => {
this.settingsSubmenu.push(child)
});
});
}
**in HTML File**
<ng-container *ngFor="let menuItem of settingsSubmenu">
<a mat-menu-item >{{menuItem.title}}</a>
</ng-container>

If your questions is about Typescript error, then possible two solutions:
Modify tsconfig.json to ignore Typescript error:
{
...
"angularCompilerOptions": {
...
"strictTemplates": false
}
}
Modify your code to compile without errors:
In *.component.ts file add import:
import {OutletPosition} from '#spartacus/storefront';
and define variable:
outletPosition = OutletPosition;
In *.component.html file:
[cxOutletPos]="outletPosition.BEFORE"

Related

Vue class components dynamically add component depending on answer from backend

So from the backend I get a array of objects that look kind of like this
ItemsToAdd
{
Page: MemberPage
Feature: Search
Text: "Something to explain said feature"
}
So i match these values to enums in the frontend and then on for example the memberpage i do this check
private get itemsForPageFeatures(): ItemsToAdd[] {
return this.items.filter(
(f) =>
f.page== Pages.MemberPage &&
f.feature != null
);
}
What we get from the backend will change a lot over time and is only the same for weeks at most. So I would like to avoid to have to add the components in the template as it will become dead code fast and will become a huge thing to have to just go around and delete dead code. So preferably i would like to add it using a function and then for example for the search feature i would have a ref on the parent like
<SearchBox :ref="Features.Search" />
and in code just add elements where the ItemsToAdd objects Feature property match the ref
is this possible in Vue? things like appendChild and so on doesn't work in Vue but that is the closest thing i can think of to kind of what I want. This function would basically just loop through the itemsForPageFeatures and add the features belonging to the page it is run on.
For another example how the template looks
<template>
<div class="container-fluid mt-3">
<div
class="d-flex flex-row justify-content-between flex-wrap align-items-center"
>
<div class="d-align-self-end">
<SearchBox :ref="Features.Search" />
</div>
</div>
<MessagesFilter
:ref="Features.MessagesFilter"
/>
<DataChart
:ref="Features.DataChart"
/>
So say we got an answer from backend where it contains an object that has a feature property DataChart and another one with Search so now i would want components to be added under the DataChart component and the SearchBox component but not the messagesFilter one as we didnt get that from the backend. But then next week we change in backend so we no longer want to display the Search feature component under searchbox. so we only get the object with DataChart so then it should only render the DataChart one. So the solution would have to work without having to make changes to the frontend everytime we change what we want to display as the backend will only be database configs that dont require releases.
Closest i can come up with is this function that does not work for Vue as appendChild doesnt work there but to help with kind of what i imagine. So the component to be generated is known and will always be the same type of component. It is where it is to be placed that is the dynamic part.
private showTextBoxes() {
this.itemsForPageFeatures.forEach((element) => {
let el = this.$createElement(NewMinorFeatureTextBox, {
props: {
item: element,
},
});
var ref = `${element.feature}`
this.$refs.ref.appendChild(el);
});
}
You can use dynamic components for it. use it like this:
<component v-for="item in itemsForPageFeatures" :is="getComponent(item.Feature)" :key="item.Feature"/>
also inside your script:
export default {
data() {
return {
items: [
{
Page: "MemberPage",
Feature: "Search",
Text: "Something to explain said feature"
}
]
};
},
computed: {
itemsForPageFeatures() {
return this.items.filter(
f =>
f.Page === "MemberPage" &&
f.Feature != null
);
}
},
methods: {
getComponent(feature) {
switch (feature) {
case "Search":
return "search-box";
default:
return "";
}
}
}
};

How to differentiate component in angular 6

I am trying to create a global component but that is working same like in all places..i want to use with different label values and in many palaces like aglobal component.I am learning angular 6 so facing trouble now. How do it to resolve?
service:
addComp(Names,c){
let item = {name: Names, componentid: c};
if (this.item.find((test) => test.name === Names) === undefined) {
this.item.push(item);
}
}
You can use the #Input decorator to declare values in your BreadcrumbDemoComponent that you want to be different, and pass those values as properties in the selector tag.
Example:
app-component.html
<breadcrumb-demo [label]="'Value 1'"></breadcrumb-demo>
<breadcrumb-demo [label]="'Value 2'"></breadcrumb-demo>
breadcrumb-demo.component.ts
...
export class BreadcrumbDemoComponent {
#Input() label;
...
}
breadcrumb-demo.component.html
...
<h1>{{ label }}</h1>
...

Kendo UI + Vue - stable sorting groups in Chrome

I am using the Vue wrapper for Kendo UI and can't get sorting to work in Chrome.
I am trying to group my data into sites and order the rows by categories in those sites.
My first column in Vue is a hidden one with the category index to sort them:
<kendo-grid-column field="___categorySortingIndex" :hidden="true"></kendo-grid-column>
If I do not enable grouping on my dataSource then it orders all the categories as expected after the index number.
The issue I am dealing with only occurs when grouping the items:
group: {
field: "___siteSortingIndex",
dir: "asc"
}
There is a tutorial on it using Kendo jQuery but the functionality does not seem to work for the vue components since vue uses template syntax instead of an array of objects like the jQuery example does.
The jQuery tutorial solution:
...
columns: [{
field: "Name"
}, {
field: "Address",
sortable: {
compare: function(a, b, descending) {
if(a.Address !== b.Address)
{
return a.Address - b.Address;
}
if (descending) {
return b._position - a._position;
} else {
return a._position - b._position;
}
}
}
}]
...
Trying to do it in Vue:
<kendo-grid-colum :sortable="sortableObject" ...>
...
sortableObject = {
compare: ( a, b, descending ) => {
...
}
};
...
Setting the sortable prop to an object gives the following warning:
[Vue warn]: Invalid prop: type check failed for prop "sortable". Expected Boolean, got Object.
Is there a way to stable sort for chrome using the vue wrapper to kendo ui?
The :sortable property in the grid column only takes a Boolean type.
However, there is a :sortableCompare property that takes a Functionthat should return an object with sortable.comparein a similar way to the jQuery example you posted.
I solved this by listening to the #databinding event:
<kendo-grid ... #databinding="onDataBinding" ...>
This event runs before the template is rendered and it is possible to then sort the data before it is used in the kendo vue template:
onDataBinding( e ) {
forEach( e.items, item => {
item.items.sort( ( a, b ) => a.___categorySortingIndex - b.___categorySortingIndex );
} );
}
Whether or not this is considered bad I can't say, but it did work for what I needed it to do.

V-select bug while selecting elements in Vuejs

I'm building a small application in vuejs 2 where I'm using v-select package for select box, Problem I'm facing is:
I've declared v-select in my component something like this:
<div class="form-group"><label class="col-sm-2 control-label">Company name:</label>
<div class="col-sm-6">
<v-select :options="companyOptions" v-model="company_name" :on-search="getOptions" placeholder="Company name"></v-select>
</div>
</div>
So accordingly I'm having data defined as company_name, and I'm calling an axios event to get the searchable data, while the component is being loaded I'm calling index data of first 50 set for initial selection and if anybody types then I'm calling a function getOptions to get data related to the input, now suppose if somebody selects any data and then removes it again from the selection and again search with key press event the searchable data is not displayed, I can see that my axios call is working fine and I'm able to get the relevant data. but it is not displaying in dropdown as it says:
Error in render function: "TypeError: Cannot read property 'label' of null"
Which is coming from the company_name model which was selected. Following is my code in codepen
In this my axios is not working as it says mixed content:
https://codepen.io/anon/pen/Bdeqam?editors=1011' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://connect.stellar-ir.com/api/companies'. This request has been blocked; the content must be served over HTTPS.
So I'm unable to explain properly in this code set. But my code looks same as declared in codepen.
Help me out in this.
The error is because your computed values are undefined and undefined is not a string, so no string methods (toLowerCase()) are available. The response.data.model.data must look like this:
[
{
id: 1234,
name: 'example'
}, {
id: 12345,
name: 'example2'
}
]
if you get an object instead of an array push it to the array: this.serverData.push(response.data.model.data)
Replace your axios call with:
this.serverData = [
{
id: 1234,
name: 'example'
}, {
id: 12345,
name: 'example2'
}
]
to test it.
In your getOptions() method you calling loading(true or false), but your fetchIndexData() method has an asynchronous axios call. Use async/await, a callback function or a promise chain to wait for the data and show the loading indicator correctly.
On every keypress an request is send to the server i would recommend to use a debounce function.
Tipp
Line 42: https://stackoverflow.com/a/42028776/6429774
axios.post('http://connect.stellar-ir.com/api/companies', searchData).then(response => {
if(response.status === 200)
{
this.serverData = response.data.model.data
}
}).catch(error => {
console.log(error)
});

access object with dynamic variable vue.js

This is my object
var users ={
twitter : {
name : //,
lastname : //
},
facebook : {
name : //,
lastname : //
}
}
}
I have a dynamic variable activeuser that updates from Facebook to twitter.
What i'm trying to do is refer to the inner object in users depending on the value of activeuser. I need to give my div something like this class :
<div class=' {{users.activeuser}}'></div>
I know this is not how it should be done with vue.js. Do you have any suggestions?
Thank You!
Using VueJS you should be able to assign your dynamic variable to a Vue Model when you load the new object using a Vue setter $set('property name', 'value')
Example AJAX retreival:
$.getJSON('myURL.html?query=xxx', function(data, textStatus, jqXHR){
try{
MyVue.$set('dynamicObject', data);
}
catch(e){}
});
A generic Vue may look like this:
var MyVue = new Vue({
el:'#exampleDiv',
data: {
dynamicObject : ''
}
});
Bound to an example HTML element:
<div id="exampleDiv">
<label class="{{dynamicObject.activeuser}}">{{dynamicObject.username}}</label>
</div>
In the case that you have an object with an array of objects which also contain properties Vue makes it very simple to create many HTML elements (for each child object) by simply adding a v-repeat (example) to the desired HTML and assigning the datasource:
<div id="exampleDiv">
<label v-repeat="dynamicObject" class="{{dynamicObject.activeuser}}"></label>
</div>