How to display custom data in Mgt Person in SPFX - spfx

I want to display custom data which is coming from an API which will have data in 4 lines in Person Mgt,
I don't want to use default data from personquery, so how can I pass list of people's data in the Person Mgt also by default it shows data in just three lines but I want to display 4 details of an individual in 4 different lines in SPFX.
I've provided sample implementation of the code,
public render(): React.ReactElement<IMgtComponentsProps> {
return (
<Person
personQuery="me"
//personDetails={personDetails}
view={ViewType.threelines}
fetchImage={true}
avatarType={avatarType.photo}
personCardInteraction={PersonCardInteraction.hover} />
);
}
I'll be having similar type of custom data as shown below so I want to show these details as per user.
const personDetails = {
displayName: 'Bill Gates',
mail: 'nikola#contoso.com',
role:'Developer',
community:'Software Enginnering'
}
I tried passing this object inside personDetails property of Person but it's not working.

Currently a fourth line of data is only support via a custom rendering template
Here's an example of that using the raw web component as opposed to the React Wrapper.
<mgt-person class="my-person" person-query="me">
<template>
<div>
Hello, my name is: {{person.displayName}} <br>
{{person.role}} <br>
{{person.community}} <br>
{{person.mail}}
</div>
</template>
<template data-type="loading">
Loading
</template>
</mgt-person>
const person = document.querySelector('.my-person');
person.personDetails = {
displayName: 'Bill Gates',
mail: 'nikola#contoso.com',
role: 'Developer',
community: 'Software Enginnering'
};
With the existing three line view you can map each of the lines to your custom properties, assuming you have the above custom data being passed correctly you can have the component render the chosen properties on each line.
<mgt-person
class="my-person"
view="threeLines"
line2-property="role"
line2-property="community"
person-card="hover"
fetch-image>
</mgt-person>
The good news for the four-line case is that we are adding that to the library as part of our v3 release which is currently being worked on.

Related

How can I create components from markdown in Gatsby like a page?

I am learning Gatsby and trying to expand their tutorial, which leaves you with a blog-like site. Each post is generated from markdown files, queried with Graphql and processed via onCreateNode and createPages.
I'd like to create markdown files for author bios that can be included on these generated pages. Then if a bio changed, the markdown would be changed in one place, instead of manually changing each markdown file written by that author.
Is it possible to have a similar, generated workflow for components? Or could I pass the author's name/bio file name to a component that does a query and processes the resulting markdown?
Edit: As I've considered this, I don't see much benefit of a markdown for my bios vs a component. Would it be bad form to have a component AuthorBio for the format and several components like JohnDoeBio or JaneSmithBio that return an AuthorBio with some information passed in props to render for them? I am fairly certain I can reference these components from my markdown or let my template choose them based on frontmatter, though that might lead to a large switch...
I had the exact same thought process! This is how I solved it:
BlogPostTemplate.jsx
<Layout>
<ShortBio {...authorData} /> // show the author bio on top of the blog post
<div
className="blog-post"
dangerouslySetInnerHTML={{ __html: html }} // your markup as HTML
/>
</Layout>
ShortBio.jsx
export const ShortBio = ({ authorPic, authorName, datePublished, readingTime }) => {
const postInfo = `${readingTime} ยท ${datePublished}`;
return (
<AuthorDiv>
<ImageAvatars src={authorPic} alt={authorName} />
<TextStylesDiv>
<Typography>{author}</Typography>
<Typography>{shortBioText}</Typography>
<Typography>{postInfo}</Typography>
</TextStylesDiv>
</AuthorDiv>
);
};
GraphQL:
export const blogQuery = graphql`
query ($slug: String!) {
blog: markdownRemark(fields: {slug: {eq: $slug}}) {
html
frontmatter {
title
date(formatString: "DD MMMM YYYY")
author
}
excerpt(pruneLength: 165)
fields {slug}
wordCount {
words
}
}
}
`;
Use the power of Gatsby and GraphQL and determine the author by its metadata in the markup. Look at the GraphQL query: I have an author tag defined therefore I can dynamically set an author just in the markup of the blog post.
Or could I pass the author's name/bio file name to a component that
does a query and processes the resulting markdown?
Yes, use an author tag in the frontmatter of your markdown.
---
title: Hello World
date: "2018-01-15"
author: "Solid Snake"
---
Edit: As I've considered this, I don't see much benefit of a markdown
for my bios vs a component. Would it be bad form to have a component
AuthorBio for the format and several components like JohnDoeBio or
JaneSmithBio that return an AuthorBio with some information passed in
props to render for them? I am fairly certain I can reference these
components from my markdown or let my template choose them based on
frontmatter, though that might lead to a large switch...
Creating several static author components is fine if you can confidently state that the the amount of author stays small. Be pragmatic. Do it like you said.

How to pass dynamic ajax-url for vue-select while function called for search event?

I want to make use one function for multiple component in vue-js. To do so i need to make two things dynamic - 1.ajax-url and 2. dataset holder for options. I read https://sagalbot.github.io/vue-select/docs/Advanced/Ajax.html as per this function working fine. i have following code-
<v-select :options="fieldSet[name].dataSet" :url="/user/autocomplete?term=" #search="onSearch">
<template slot="no-options">
<button class="btn btn-block">Add New Item</button>
</template>
</v-select>
onsearch method is as follows as given in above link -
// here search and load parameter gives searchText and spinner for UX
onSearch: function onSearch(search, loading) {
loading(true);
// this.search(loading, search, this);
// here i want to get options holder and ajax-url so that i can
// fetch data using ajax and assign to some dynamic variable (which is defined for particular field)
},
What i looked into is -
Use dynamic AJAX URL for Vue Select2 wrapper component
, but could not determine what to do for v-select.
Some time before I faced same problem, i made following changes on /node_modules/vue-select/dist/vue-select.js and changes are equals to changes in two files -- /node_modules/vue-select/src/mixins/ajax.js and /node_modules/vue-select/src/components/select.vue,
It has two steps first change $emit.function parameters and register your new variable as props
make search for onSearch:{type:Function,default:function(t,e){}}} and i made it like onSearch:{type:Function,default:function(t,e,url){}}} because this make search function will return three parameters..
and search for watch:{search:function(){this.search.length>0&&(this.onSearch(this.search,this.toggleLoading), and change it to watch:{search:function(){this.search.length>0&&(this.onSearch(this.search,this.toggleLoading,this.ajaxUrl,this.optionHolder), because this will return 4 parameters ajaxUrl and optionHodler and watch them ,
now we need to return them using $emit
make a search for this.$emit("search",this.search,this.toggleLoading))} and change it to this.$emit("search",this.search,this.toggleLoading,this.ajaxUrl,this.optionHolder))} this will return four variables making them accessible globally ...
Now register your new parameter in select.vue file by changing following -
make search forprops:{value:{default:null}, and place these two these ajaxUrl:{type:String,default:''},optionHolder:{type:String,default:''}, defination after search text ...
this is working for me ... let me know whether it worked for you or not?

OpenUI5: Issue with adding a view to an element

I try to include an HTML-View in a XML-View which actually shouldn't be a problem. Unfortunately the content of the HTML-View is not added to the site. An error is not thrown.
In the XML-View I have a placeholder for the HTML-View:
<html:div
id="helptext">
</html:div>
In the controller of the XML-View I instantiate the HTML-View and add it to the placeholder:
var oController = sap.ui.controller("dividendgrowthtools.view.textviews.dividendcomparehelpDE");
var oTextView = sap.ui.view({
viewName: "dividendgrowthtools.view.textviews.dividendcomparehelpDE",
controller: oController,
type: sap.ui.core.mvc.ViewType.HTML
});
var oHelpText = this.getView().byId("helptext");
oTextView.placeAt(oHelpTextDiv.sId);
That's the content of the HTML-View:
<template data-controller-name="dividendgrowthtools.view.textviews.dividendcomparehelpDE">
<p>This is a test.</p>
</template>
Does anybody have an idea what the problem could be?
you need to be aware of the functionality of this.getView().byId();
SAPUI5 generates another ID then the one you specified in the XML-View("helptext") see:
So you need to pass the right ID. You need to be aware that these ID could possibily change, when you refactor the XML structure.
I would recommend you, not to use HTML elements in SAPUI5.
Some helpful links:
https://scn.sap.com/thread/3551589
https://plnkr.co/edit/wDBpQuxIWd0WGOoyulN0?p=preview (made by me)PLnkr Link

Form select box in Backbone Marionette

I'm trying using Backbone.Marionette to build an application. The application gets its data through REST calls.
In this application I created a model which contains the following fields:
id
name
language
type
I also created an ItemView that contains a complete form for the model. The template I'm using is this:
<form>
<input id="model-id" class="uneditable-input" name="id" type="text" value="{{id}}"/>
<input id="model-name" class="uneditable-input" name="name" type="text" value="{{name}}" />
<select id="model-language" name="language"></select>
<select id="model-type" name="type"></select>
<button class="btn btn-submit">Save</button>
</form>
(I'm using Twig.js for rendering the templates)
I am able to succesfully fetch a model's data and display the view.
What I want to do now is populate the select boxes for model-language and model-type with options. Language and type fields are to be restricted to values as a result from REST calls as well, i.e. I have a list of languages and a list of types provided to me through REST.
I'm contemplating on having two collections, one for language and one for type, create a view for each (i.e. viewLanguageSelectOptions and viewTypeSelectOptions), which renders the options in the form of the template I specified above. What I am not sure of is if this is possible, or where to do the populating of options and how to set the selected option based on data from the model. It's not clear to me, even by looking at examples and docs available, which Marionette view type this may best be realized with. Maybe I'm looking in the wrong direction.
In other words, I'm stuck right now and I'm wondering of any of you fellow Backbone Marionette users have suggestions or solutions. Hope you can help!
Create a view for a Select in my opinion is not needed in the scenario that you are describing, as Im assuming that your languages list will not be changing often, and the only porpouse is to provide a list from where to pick a value so you can populate your selects in the onRender or initializace function of your view using jquery.
you can make the calls to your REST service and get the lists before rendering your view and pass this list to the view as options and populate your selects on the onRender function
var MyItemView = Backbone.Marionette.ItemView.extend({
initialize : function (options) {
this.languages = options.languages;
this.typeList = options.typeList;
},
template : "#atemplate",
onRender : function () {
this.renderSelect(this.languages, "#languagesSelect", "valueofThelist");
this.renderSelect(this.typeList, "#typesSelect", "valueofThelist")
},
renderSelect :function (list, element, value) {
$.each(list, function(){
_this.$el.find(element).append("<option value='"+this[value]+"'>"+this[value]+"</option>");
});
}
})
var languagesList = getLanguages();
var typeList = getTypesList();
var myItemView = new MyItemView({languages:languagesList,typeList :typeList });
Hope this helps.

Understanding Ember Views

I'm looking for some clarification on views in Ember.js
Coming from a rails background and I'm trying to ignore any preconceptions. From what I understand of the ember framework there are 5 components:
Routes: This is where we define the state of the application. The state is reflected in the URL. We can also define data loading here. Route classes are defined and on startup ember creates route objects which last for the duration of the application.
Models: This is where object data is defined. Can also define computed properties. A model object is created for each json object returned from the server.
Controllers: This mediates interactions between the models and templates/views. Controller classes are defined and on startup ember creates controller objects which last for the duration of the application. There is only ever a single instance of each controller class.
Templates: These describe the generated markup.
Views: These are specific templates or dom elements relating to a model. These are used to define interface events and send them to the controller for handling. Not sure when to create these.
As an example lets say I have a EventsController that has data loaded on the applicationRoute:
ScheduleApp.EventsController = Ember.ArrayController.extend();
ScheduleApp.ApplicationRoute = Ember.Route.extend({
setupController: function() {
this.controllerFor('events').set('content', ScheduleApp.Event.find());
}
});
Now in my template instead of iterating over each and displaying the information I want to iterate over each and create an associated view so I can add interactions to each event. I presume I would need to create a new view for each event and have it display in my template. However, I'm not sure where I create these views. Do I define a view class and then ember will create a new view object each time I call it using the view helper? Eventually I would like to use the appendTo on the view to inject my events to different places in the dom. Where would this be defined?
I've tried reading over the ember.js guide for views but it describes the context of a creating a single view. I think I want to make many views for each event and then dynamically interact with those objects.
Up to now ember has been outrageously clever so I would assume there is a built in method for generating these views. After all, most user interfaces are full of lists that require interactions. The problem is the list I'm trying to make I then want to spread over the dom depending on its attributes.
As per your code, App.EventsController has a list of events, now let us say we want the UI to have a list of events displayed and for each event say we want the view to have a delete button which deletes the event when the user clicks
One way to accomplish is by using Ember.CollectionView, the collection view as the name suggests is tailored for these sort of requirements, in many Ember examples the usage of view is not defined because ember auto-generates it for you but in some cases we might need to explicitly define a view to meed our requirements
App.EventsView = Ember.CollectionView.extend({
// It needs a list of data to iterate upon
// We are binding it to the controllers content data which
// is a list of events
contentBinding: "controller.content",
appendSpan: function(){
view = Ember.View.create({tagName: 'span'});
this.get("childViews").forEach(function(child){
view.appendTo(child);
});
},
// Now we need to also define a view template that will be
// generated for all the elements in the content array
// This could in turn be another collection view if required
// I am going to keep it simple for now
itemViewClass: Ember.View.extend({
templateName: "event",
deleteEvent: function(){
// Implement Delete
this.get("content").deleteRecord();
},
notifyUser: function(){
// The record doesn't get deleted as soon as user clicks, the request goes to
// server and server deletes the record and sends back the response to the
// client, Hence I'm using an observer here on isDeleted property of the record
if(this.get('content.isDeleted')){
alert("Record deleted Successfully");
}
}.observes('content.isDeleted')
})
})
Important Note Inside the CollectionView definition this.get("content") refers to the array of events, while in itemViewClass this.get("content") refers to the single event object
//Defining the template
//Assuming the event model has a name property
<script type="text/x-handlebars" data-template-name="event">
Name: {{view.content.name}}
<a {{action deleteEvent target="view"}} href="#">Delete Event</a>
</script>
Now when you hit your application_url/events
you'll a list of events each event has a delete button, I hope this clears some concepts
For more information about CollectionView
Update as per the comment:
If you want to append another view to each child view, you can do so by editing the template of itemViewClass as follows
<script type="text/x-handlebars" data-template-name="event">
Name: {{view.content.name}}
<a {{action deleteEvent target="view"}} href="#">Delete Event</a>
{{ view App.SomeOtherView }}
</script>
it can be a partial too as follows
<script type="text/x-handlebars" data-template-name="event">
Name: {{view.content.name}}
<a {{action deleteEvent target="view"}} href="#">Delete Event</a>
{{ partial "somePartial" }}
</script>
or if you want to do it programmatically say, you click a button in the EventsView template and on click all the childs view must have a span tag appended to it(I am very bad at giving examples)
//This is the template for App.EventsController,
//template-name = "events" => view is App.EventsView and controller App.EventsController
<script type="text/x-handlebars" data-template-name="events">
<a {{action appendSpan target="view"}} href="#"> Append </a>
</script>
appendSpan is defined in the CollectionView

Resources