I am trying to add this list into my view model in order to make some bindings a little bit simpler. However, I can't figure out the syntax in order to do so.
var images = [
{ name: "Image 1", photo: "/images/image1.jpg" },
{ name: "Image 2", photo: "/images/image2.jpg" },
{ name: "Image 3", photo: "/images/image3.jpg" },
];
var viewModel = {
favorite: "",
...
}
Assign images to viewModel like this:
var viewModel = {
favorite: "",
images: images
};
Then access them like this viewModel.images
Related
I am working on an offer letter template that will replace/modify Dynamic Data Points like Name, Address, Role, Salary, etc based on the candidate selected from a list of candidates. There is a fixed syntax for a dynamic data points i.e they will be enclosed within <<>>, for example :
Welcome to the family, <<Name>>
You will be paid <<Salary>> for the duration of your employment.
In other words, these few data points will change by selecting the candidate we want to offer the job and the rest of the template will remain the same. Here is a demo to help you understand.
This is a dummy array I have created with 1 template, In the real-world app, I can have many templates with different clauseNames, so I am looking for a permanent fix.
.ts file, Template List :
[{
templateId: 1,
templateName: "Offer",
clauses: [
{
clauseName: "Introduction",
clauseId: 1,
texts: [
{
text: "Hello <<Name>>, Welcome to the Machine",
textId: 1,
}]
},
{
clauseName: "Address",
clauseId: 2,
texts: [
{
text: "<<Address>>",
textId: 2,
}]
},
{
clauseName: "Date Of Joining",
clauseId: 3,
texts: [
{
text: "You can join us on <<DateOfJoining>>",
textId: 3,
}]
},
]
}]
and here is the candidate list,
candidateList = [
{ name: "Simba", address: "Some Random Cave" },
{ name: "Doe John", address: "line 4, binary avenue, Mobo" },
{ name: "B Rabbit", address: "8 mile road, Detroit" },
{ name: "Peter Griffin", address: "Spooner Street" },
{ name: "Speedy Gonzales", address: "401, hole 34, Slyvester Cat Road" },
{ name: "Morty", address: "Time Machine XYZ" },
{ name: "Brock", address: "pokeball 420, Medic center" },
]
You can use regular expressions to replace those placeholders such as:
var result = text.text.replace(/\<\<(.*?)\>\>/g, function(match, token) {
return candidate[token.toLowerCase()];
});
One way to incorporate this to your display is by creating a property that returns the formatted text.
I have updated your stackblitz here.
Take a look at this demo
I have modified the logic in below method:
showTeplate(name,address,doj) {
this.clauseList = [];
for (let a of this.templateList) {
if (a.clauses != null) {
for (let cl of a.clauses) {
const tempObj = JSON.parse(JSON.stringify(cl));
tempObj.texts.forEach(textObj => {
textObj.text = textObj.text.replace("<<Name>>",name);
textObj.text = textObj.text.replace("<<Address>>",address);
textObj.text = textObj.text.replace("<<DateOfJoining>>",doj);
})
this.clauseList.push(tempObj)
}
}
}
console.log("Clause list", this.clauseList)
}
I am storing a java script object in the DB by converting that into the string by using JSON.stringify, But when i want to retrieve that object from DB i use the JSON.parse. But the JSON.parse is not returning the original object. In the below console screenshot it can be seen that the object Obj had some changes after it is converted into string and then parsed. So how can i get back the original object after doing JSON.stringify
The Object is as below:
var Obj = {
onchange: function(){
},
validate: function(obj){
},
elements: {
"list": {
menu: [{
caption: "Append an",
action: Xonomy.newElementChild,
actionParameter: "dd"
}]
},
"item": {
menu: [{
caption: "Add ",
action: Xonomy.newAttribute,
actionParameter: {name: "label", value: "something"},
hideIf: function(jsElement){
return jsElement.hasAttribute("label");
}
}, {
caption: "Delete this ",
action: Xonomy.deleteElement
}, {
caption: "New before this",
action: Xonomy.newElementBefore,
actionParameter: "sas"
}, {
caption: "New after this",
action: Xonomy.newElementAfter,
actionParameter: "aa"
}],
canDropTo: ["list"],
attributes: {
"label": {
asker: Xonomy.askString,
menu: [{
caption: "Delete this",
action: Xonomy.deleteAttribute
}]
}
}
}
}
};
As already mentioned in comments - you can't serialize JS functions with JSON.stringify. Please take a look at serialize-javascript library to store the functions.
I'm currently working with vuejs and vuex. Here is my issue :
I have a store with all the data
state: {
articles: [{
title: "Article 1",
id: 1,
tag: "Tutorial"
}, {
title: "Article 2",
id: 2,
description: "Article 2",
tag: "Review"
}
}]
}
On the homepage, I want to display all kind of articles. On the tutorial page I only want to display articles with tag "tutorial", etc...
I'm using vue-router. I'm working with a computed property and a v-for so I can loop in the articles.
computed: {
articles() {
if (this.$route.meta.title == 'Tutorial') {
return this.$store.state.articles.tag == 'Tutorial'
}
if (this.$route.meta.title == 'Review') {
return this.$store.state.articles.tag == 'Review'
}
else if (this.$route.meta.title == 'Home') {
return this.$store.state.articles
}
}
}
I know that return this.$store.state.articles.tag == 'Tutorial' can't work, I'm looking for a way to code it correctly but I'm stuck!
Also, if you have a completely different and better way to do it, feel free to tell me!
Thank you for your time :)
As everybody mentioned you will need to use filter but as a pattern you should structure it with vuex getters
when you access properties from vuex state do not to access them directly but the correct thing is to use getters
Vuex store e.x.
const store = new Vuex.Store({
state: {
articles: [
{
title: "Article 1",
id: 1,
tag: "Tutorial"
},
{
title: "Article 2",
id: 2,
description: "Article 2",
tag: "Review"
}
]
},
getters: {
allArticles: state => {
return state.articles
},
tutorialArticles: state=>{
return state.articles.filter(article=>articles.tag=='Tutorial')
},
reviewArticles: state=>{
return state.articles.filter(articles=>articles.tag=='Review')
}
}
})
//end of vuex store
Then in your "all articles" component you use
computed:{
articles(){
return this.$store.getters.allArticles;
}
}
Then in your tutorial articles component you use
computed:{
articles(){
return this.$store.getters.tutorialArticles;
}
}
This is very important because if you need to change the code for the filter method you do it in one place and thats the purpose of using Vuex
Probably the best way is using .filter()
var obj = {state: {
articles: [{
title: "Article 1",
id: 1,
tag: "Tutorial"
}, {
title: "Article 2",
id: 2,
description: "Article 2",
tag: "Review"
}
]}}
var filtered = obj.state.articles.filter(o=>o.tag == "Tutorial");
console.log(filtered)
I'm very new to angularjs and need some advice about the angular way to implement something very simple. In my $scope I need to set some field defaults, and these defaults are needed multiple times in my controller.
I want to be able to refactor these defaults out to a common place, to thin out the controller and allow for code reuse, but not sure if this should be a factory, directive or service.
Heres an example of the defaults:
$scope.skills = [{
description: '',
years: "1",
level: "0",
years_values: [
{ id: "1", description: "1" },
{ id: "2", description: "2" },
{ id: "3", description: "3+" }],
level_values: [
{ id: "0", description: "Starter"},
{ id: "1", description: "Intermediate"},
{ id: "2", description: "Advanced"} ]
}]
Here's an example of where I'd like to call the "new function":
skillSuccess = (resp)->
Loader.hide();
$rootScope.current_user = resp;
#TODO replace this repetition
$scope.skills = [{
description: '',
.... etc
My questions are:
Should I use a factory/directive/service, (or something else) for
this refactoring?
How do I ensure that the function gets called
initially so that the default values are available for the fields
when the page loads?
Should I use a factory/directive/service, (or something else) for this
refactoring?
I'd suggest you to create a constant because looks like you have defaults data which has initially has some value and that will going to be change by the user from the front-end. So you could place that in angular constant, then that constant will be accessed by the factory/service. And Factory/service will do the needful manipulation from its function. To make available constant in your service/factory you need to inject constant name in your service.
By looking at your current requirement you shouldn't be take consideration of directive component.
Constant
app.constant('defaults', [{
description: '',
years: "1",
level: "0",
years_values: [
{ id: "1", description: "1" },
{ id: "2", description: "2" },
{ id: "3", description: "3+" }],
level_values: [
{ id: "0", description: "Starter"},
{ id: "1", description: "Intermediate"},
{ id: "2", description: "Advanced"} ]
}]);
Service
app.service('dataService', function(defaults){
var dataService = this;
dataService.defaults = defaults;
dataService.defaults = angular.copy(defaults) //will return same copy every-time
dataService.getDefaults = function(){
return dataService.defaults;
}
//other method will lie here
})
How do I ensure that the function gets called initially so that the default values are available for the fields when the page loads?
You could simply get that defaults by consuming getDefaults method of your service, then stored that retrieved defaults and use those for manipulation.
If you want the defaults copy to instantiated every-time then use angular.copy(defaults) which will give you the copy of defaults.
Controller
app.controller('myCtrl', function($scope, dataService){
$scope.defaults = dataService.getDefaults(); //this will have defaults
//...other stuff here...
});
Should I use a factory/directive/service, (or something else) for this refactoring?
A controller should be used to set the scope, but the default values should be stored as a constant and returned by a factory. A factory pattern is preferred here because it is a singleton.
angular.module('myApp')
.factory('skillsFactory', function (defaultSkills) {
var service = {};
service.getDefaults = function () {
return defaultSkills;
};
return service;
})
.constant('defaultSkills', [{
description: '',
years: "1",
level: "0",
years_values: [{
id: "1",
description: "1"
}, {
id: "2",
description: "2"
}, {
id: "3",
description: "3+"
}],
level_values: [{
id: "0",
description: "Starter"
}, {
id: "1",
description: "Intermediate"
}, {
id: "2",
description: "Advanced"
}]
}]);
How do I ensure that the function gets called initially so that the default values are available for the fields when the page loads?
In your controller, call $scope.skills = skillsFactory.getDefaults();
angular.module('myApp')
.controller('skillsCtrl', function ($scope, skillsFactory) {
$scope.skills = skillsFactory.getDefaults();
});
I have these models:
TravelClient.Tour = DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
seats: DS.attr('number'),
takenSeats: DS.hasMany('TravelClient.TakenSeat', {embedded:'always'})
TakenSeats: function() {
console.log(this.get('takenSeats').toArray())
}.property('takenSeats')
});
TravelClient.TakenSeat = DS.Model.extend({
tour: DS.belongsTo('TravelClient.Tour'),
number: DS.attr('number')
});
JSON looks like this:
{
"tours": [
{
"id": "5110e8b5a8fefe71e0000197",
"title": "qui deserunt dolores",
"description": "Id velit nihil.",
"seats": 12,
"taken_seats": [
{
"id": "5110e8b5a8fefe71e0000196",
"number": "5"
},
{
"id": "5110e8b5a8feffffe0000196",
"number": "2"
}]
}
But yeah, when I do console.log(this.get('takenSeats').toArray() in Tour model's method, it returns Uncaught TypeError: Cannot call method '_create' of undefined, so, it seems that takenSeats did not load with parent model. What's wrong?
UPDATE
added tour_id to JSON, but now, when I want to use calculated property:
freeSeats: function() {
var seats = this.get('seats');
var takenSeats = this.get('takenSeats');
if (takenSeats) {
return (seats - takenSeats.length);
}
else {
return seats;
}
}.property('seats', 'takenSeats')
takenSeats is undefined.
UPDATE 2:
TravelClient.RESTSerializer = DS.RESTSerializer.extend({
init: function() {
this._super();
this.map('TravelClient.Tour',{
images:{embedded:'always'},
options:{embedded:'always'},
takenSeats:{embedded:'always'}
});
}
});
TravelClient.CUSTOMAdapter = DS.RESTAdapter.extend({
bulkCommit: false,
serializer: TravelClient.RESTSerializer.create(),
url: "http://192.168.1.27:3000",
buildURL: function(record, suffix) {
var s = this._super(record, suffix);
return s + ".json";
}
});
TravelClient.Store = DS.Store.extend({
revision: 11,
adapter: TravelClient.CUSTOMAdapter.create()
});
TravelClient.store = TravelClient.Store.create();
the TakenSeats computed property is perceived as a class because it's capitalized. Next to that embedded loading has to configured differently. Like so: This way the tour object becomes dirty when a takenseat changes.
DS.RESTAdapter.map('TravelClient.Tour', {
takenSeats: { embedded: 'always' },
});
Or: This way the tour doesn't become dirty.
DS.RESTAdapter.map('TravelClient.Tour', {
takenSeats: { embedded: 'load' },
});
Do this before you initialize your Store and Adapter. This will make the computed property unnecessary. You can just do tour.get('takenSeats');
Oh and you don't have to specify that the type is embedded anymore. The id's in the taken_seats array that link back to the tour need to be called tour_id.
{
"tours": [{
"id": "5110e8b5a8fefe71e0000197",
"taken_seats": [{
"id": "5110e8b5a8fefe71e0000196",
"tour_id": "5110e8b5a8fefe71e0000197"
"number": "5"
}]
}]
}
I had a similar problem to this. ember-model doesn't map through nested objects.
Your JSON output currently has all the data nested beneath the tours root.
If you have access to the API, then i suggest trying to remove the root, otherwise look into using your as the main object and then grabbing all the nested objects from there on down.
instead of this:
"tours": [{
"id": "5110e8b5a8fefe71e0000197",
"taken_seats": [{
"id": "5110e8b5a8fefe71e0000196",
"tour_id": "5110e8b5a8fefe71e0000197"
"number": "5"
}]
}]
make it look like this:
[{
"id": "5110e8b5a8fefe71e0000197",
"taken_seats": [{
"id": "5110e8b5a8fefe71e0000196",
"tour_id": "5110e8b5a8fefe71e0000197"
"number": "5"
}]
}]
its possible my syntax is off, but this similar idea worked for me.