There are some posts about SwiftUI Builder like this. So that I can embed my content like:
struct Container<Content>: View where Content: View {
var content: Content
init(#ViewBuilder content: #escaping () -> Content) {
self.content = content()
}
var body: some View {
return content
}
}
struct ContentView: View {
var body: some View {
Container() {
Text("Content 1").tag(0)
Text("Content 2").tag(1)
}
}
}
I'm wondering if I don't pass the ViewBuilder in init. Instead I'd like to do something like:
struct ContentView: View {
var body: some View {
Container().buildContent {
Text("Content 1").tag(0)
Text("Content 2").tag(1)
}
}
}
The reason why I want to do this is because I want to mimic the TabView's tabItem.
You can't have the buildContent function mutate the Container, but you can default to having a Container that just vends an EmptyView, and the use that as a springboard for creating a new Container with your desired content.
You could achieve that sort of API like this:
struct Container<Content>: View where Content: View {
var content: Content
init(#ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
return content
}
}
extension Container where Content == EmptyView {
init() {
self.content = EmptyView()
}
/// Return a new `Container` with the given `Content` builder.
func buildContent<V : View>(#ViewBuilder content: () -> V) -> Container<V> {
Container<V>(content: content)
}
}
struct ContentView: View {
var body: some View {
Container().buildContent {
Text("Content 1").tag(0)
Text("Content 2").tag(1)
}
}
}
Related
I can't get my drag and drop with DataRepresentation to work with Transferable. I'm trying to drag and drop instances of DataSettings which is an NSManagedObject that conforms to NSSecureCoding.
Here's my UTType:
extension UTType {
static var encoderSettings = UTType(exportedAs: "com.simulator.EncoderSettings")
}
Here's my conformance to Transferable:
extension DataSettings: Transferable {
var data: Data? {
try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: true)
}
public static var transferRepresentation: some TransferRepresentation {
/*DataRepresentation(contentType: .commaSeparatedText) { setting in
let data = setting.data
print("DataRepresentation: \(data)")
return data!
} importing: { data in
print("data: \(data)")
return DataSettings()
}*/
DataRepresentation(contentType: .encoderSettings) { setting in
let data = setting.data
print("DataRepresentation: \(data)")
return data!
} importing: { data in
print("data: \(data)")
return DataSettings()
}
// ProxyRepresentation(exporting: \.title)
}
}
Here's a view where I'm testing my drop destination:
struct DropTest: View {
#State var isDropTargeted = false
var body: some View {
Color.pink
.frame(width: 200, height: 200)
.dropDestination(for: EncoderSettings.self) { setting, location in
print("\(setting)")
return true
} isTargeted: {
isDropTargeted = $0
print("Got it!!!")
}
}
}
Here's my Info plist:
The ProxyRepresentation (String) works but I need the actual Data.
The dragging starts (i.e.: I can drag the view that has the .draggable with DataSettings) but I can't drop it on my DropTest view. I can drop it on a view or app that accepts the ProxyRepresentation.
What am I missing?
i want to iterate over an array, however my array is an observer. i have tried several ways, like converting to an array. nothing works.
does anyone have a suggested solution?
i'm pretty stuck on this.
here is my code:
var vm = new Vue({
el: '#app',
data() {
return {
segmenteConfig: []
}
},
methods: {
async loadData(type) {
var url = null;
console.log("used configs -> ", this.segmenteConfig);
this.segmenteConfig.forEach(segmenteConfig => {
if (segmenteConfig.type === type) {
url = segmenteConfig.url;
console.log("used configs url -> ", url);
}
})
}
loadConfig() {
var config = [];
axios.get("ressources/segmente.json")
.then(response => {
response.data.Segmente.forEach(segmentConfig => {
this.segmenteConfig.push(segmentConfig);
});
});
}
},
created() {
this.loadConfig();
this.loadData('internet');
}
});
I've following code for my TabView:
struct CardList: View {
var body: some View {
TabView {
ForEach (0..<100 ){ item in
CardViewNew()
}
}
.tabViewStyle(PageTabViewStyle())
.padding(.vertical, 10)
}
}
Every time when I slide to the next view of my TabView the following variable "i" should increased by 1 to show the next element of my array "shuffled_questions".
struct CardViewNew: View {
var body: some View {
Text(shuffled_questions[i])
}
}
Would be nice I've someone can help me :)
Seems like there's two ways to accomplish this. To answer your original question, you could use the selection binding of TabView to get a variable to change when the TabView moves:
#State private var tabSelection = 0
var body: some View {
TabView(selection: $tabSelection) {
ForEach (0..<100 ){ item in
Text("hi")
}
}
.tabViewStyle(PageTabViewStyle())
.padding(.vertical, 10)
Text("\(tabSelection)")
}
However, it seems like in your case it seems like you may just want to pass the index from your ForEach as a parameter to your CardViewNew:
struct ContentView : View {
var body: some View {
TabView {
ForEach (0..<100 ){ item in
CardViewNew(index: item)
}
}
.tabViewStyle(PageTabViewStyle())
.padding(.vertical, 10)
}
}
struct CardViewNew: View {
var index: Int
var body: some View {
Text(shuffled_questions[index])
}
}
I use $resource service for data access from restful service. Result of $resource("path") I put in typescript domain object. Problem is that I get json in form like this:
{
"name_surname": "john_smith",
"years_of_employment": "10"
}
and I want to map it to domain object of this class:
class Employee {
constructor(public FullName: string, public YearsOfEmployment: number) { }
}
So there is mismatch between names of properties inside domain class and json fields. Is there any angularjs module I can use for mapping between those two, and what is the most elegant way to accomplish that?
I am using this in one of my projects.
It maps my shortened properties to readable properties for development.
Maybe this snippet can help you.
(function (angular) {
"use strict";
angular.module("services.mapper", []).service("mapper", [function () {
var models = {
employeeModelContract: {
name_surname: "FullName",
years_of_employment: "YearsOfEmployment"
}
};
return {
map: map,
models: models
}
function map(smallObject, contract) {
var largeObject = {};
for (var smallProperty in contract) {
if (contract.hasOwnProperty(smallProperty)) {
largeObject[contract[smallProperty]] = smallObject[smallProperty];
}
}
return largeObject;
}
}]);
})(angular);
Usage:
var mappedObject = mapper.map(yourJson, mapper.models.employeeModelContract);
UPDATE 1 (Typescript version):
class MapperService implements ng.IServiceProvider {
employeeModelContract:Object= {
name_surname: "FullName",
years_of_employment: "YearsOfEmployment"
};
$get() {
return this;
}
map(smallObject, contract): Object {
var mappedObject: Object = {};
Object.keys(contract).forEach(contractProperty => {
if (contract.hasOwnProperty(contractProperty)) {
mappedObject[contract[contractProperty]] = smallObject[contractProperty];
}
});
return mappedObject;
}
}
class Employee {
constructor(public FullName: string, public YearsOfEmployment: number) { }
}
class Controller implements ng.IController {
constructor(private mapper : MapperService){}
static $inject = ["MapperService"];
json: Object = {
"name_surname": "john_smith",
"years_of_employment": "10"
}
$onInit(): void {
var mapped = <Employee>this.mapper.map(this.json, this.mapper.employeeModelContract);
}
}
angular.module("mapper", []).controller("Controller",Controller).provider("MapperService", MapperService);
As I'm learning Angular 2 I used an observable to fetch some data via an API. Like this:
getPosts() {
return this.http.get(this._postsUrl)
.map(res => <Post[]>res.json())
.catch(this.handleError);
}
My post model looks is this:
export class Post {
constructor(
public title: string,
public content: string,
public img: string = 'test') {
}
The problem I'm facing is that the map operator doesn't do anything with the Post model. For example, I tried setting a default value for the img value but in the view post.img displays nothing. I even changed Post[] with an other model (Message[]) and the behaviour doesn't change. Can anybody explain this behaviour?
I had a similar issue when I wanted to use a computed property in a template.
I found a good solution in this article:
http://chariotsolutions.com/blog/post/angular-2-beta-0-somnambulant-inauguration-lands-small-app-rxjs-typescript/
You create a static method on your model that takes an array of objects and then call that method from the mapping function. In the static method you can then either call the constructor you've already defined or use a copy constructor:
Mapping Method
getPosts() {
return this.http.get(this._postsUrl)
.map(res => Post.fromJSONArray(res.json()))
.catch(this.handleError);
}
Existing Constructor
export class Post {
// Existing constructor.
constructor(public title:string, public content:string, public img:string = 'test') {}
// New static method.
static fromJSONArray(array: Array<Object>): Post[] {
return array.map(obj => new Post(obj['title'], obj['content'], obj['img']));
}
}
Copy Constructor
export class Post {
title:string;
content:string;
img:string;
// Copy constructor.
constructor(obj: Object) {
this.title = obj['title'];
this.content = obj['content'];
this.img = obj['img'] || 'test';
}
// New static method.
static fromJSONArray(array: Array<Object>): Post[] {
return array.map(obj => new Post(obj);
}
}
If you're using an editor that supports code completion, you can change the type of the obj and array parameters to Post:
export class Post {
title:string;
content:string;
img:string;
// Copy constructor.
constructor(obj: Post) {
this.title = obj.title;
this.content = obj.content;
this.img = obj.img || 'test';
}
// New static method.
static fromJSONArray(array: Array<Post>): Post[] {
return array.map(obj => new Post(obj);
}
}
You can use the as keyword to de-serialize the JSON to your object.
The Angular2 docs have a tutorial that walks you through this. However in short...
Model:
export class Hero {
id: number;
name: string;
}
Service:
...
import { Hero } from './hero';
...
get(): Observable<Hero> {
return this.http
.get('/myhero.json')
.map((r: Response) => r.json() as Hero);
}
Component:
get(id: string) {
this.myService.get()
.subscribe(
hero => {
console.log(hero);
},
error => console.log(error)
);
}